Is it fine to use .obs on Widgets after assing to var? - flutter-getx

Hey am Wondering is it fine to use ".obs" to widget like this :
var name= Text("foo").obs;
return name.value;

using .obs on whole widgets like this:
Rx<Widget> textWidget = Text("test").obs;
will work fine, as you can try in this exmaple:
// ...
child: Obx(
() => controller.textWidget.value,
),
and every time you assign a value to it, it will update, but this will cuase very unecessary recreating of that Text widget, since each time, a new Text widget will set in your UI, which may cause perferemnce issue.
instead you should declare primitive types as Rx observales then assignig them inside your UI widgets:
final textVal = "test".ons;
child: Obx(
() => Text(controller.textVal.value),
),

Related

Flutter. GetX the improper use of a GetX has been detected. with the RxList

RxList<ParticipantModel> participantList = RxList.empty();
........
Obx( <==== [Get] the improper use of a GetX has been detected. with the RxList
() => NCChipEditableList<ParticipantModel>(
key: const Key('StudioEditPage txt_add_main_actors'),
title: 'txt_add_main_actors'.tr.format(
[MediaConst.maxArtistTagLength],
),
addButtonText: 'txt_add_actor'.tr,
chipList: controller.media.participantList,
maxTextLength: MediaConst.maxArtistTagLength,
onAddChip: controller.onAddParticipant,
onDeleteChip: controller.onDeleteParticipant,
onEditedChip: controller.onEditedParticipant,
),
),
actually, i dont understand how to resolve this problem. I use initiated RxList as the parameter NCChipEditableList
Obx is made to update when an Rx<T> observable variable is used inside of it, so it should be used like this:
// controller
Rx<String> txt = "text".obs;
// view
Obx(() => Text(txt.value)), // works fine
if no Rx<R> variables are used inside of it :
// view
Obx(() => Text("normal raw text")), // throws the error
Then your error will be thrown from the Getx library to inform you that since there is nothing to update inside the Obx, there is no need to use it.
you should set your widget directly without wrapping with Obx if you don't need it.

Generic filter Flutter

Goodmorning,
I'm developing an app with flutter but I'm facing some problems with Provider (I think something miss in my knowledge).
My app fetch data from my API and displays them in listview.
In whole app I have different screen which displays different data type in listview and now I want to create filtering logic.
To avoid rewrite same code multiple times I thought to create one screen to reuse for filtering purposes but I'm facing problems with state management.
What I did:
create base model for filter information
`
enum FilterWidget { TEXT_FIELD, DROPDOWN } //to resolve necessary Widget with getWidget() (to implement)
class FilterBaseModel with ChangeNotifier {
String? value= 'Hello';
FilterWidget? widgetType;
FilterBaseModel(this.value, this.widgetType);
onChange() {
value= value== 'Hello' ? 'HelloChange' : 'Hello';
notifyListeners();
}
}
`
One screen for display filters depending on request
List<FilterBaseModel> filters = [];
FilterScreen() {
//Provided from caller. Now here for test purposes
filters.add(FilterBaseModel('Filter1', FilterWidget.TEXT_FIELD));
filters.add(FilterBaseModel('Filter2', FilterWidget.TEXT_FIELD));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SafeArea(
minimum: EdgeInsets.symmetric(vertical: 15, horizontal: 15),
child: SingleChildScrollView(
child: Container(
height: 400,
child: Column(
children: filters
.map(
(e) => Consumer<FilterBaseModel>(
builder: (_, filter, child) =>
ChangeNotifierProvider.value(
value: filter,
child: CustomTextField(
`your text` initialText: e.value,
onTap: () {
e.onChange();
filter.onChange();
},
),
),
),
)
.toList(),
))),
),
);
}
`
The problem is in Consumer and ChangeNotifier.value.
Screen works quite well: widget are displayed and callback are called, what is wrong? I need to use onChange method of both instance to update UI otherwhise method was called but widget is not rebuilt.
I know that probably putting consumer there is not right way but I tried also to put outside but doesn't work.
I expect to have one filter screen which receives in input filters list information, display them, handle their state managment and return their value.
P.S: this code now works, but I know is not the right way
Thank you for help!
EDIT
Have same behaviour without ChangeNotifierProvider.value. Therefore I'm more confused than before because still persist the double call to onChange for correct rebuilding.
More bit confused about ChangeNotifierProvider.value using...

How to change displayed data the best way in Flutter

i want to change displayed data in Flutter? I wrote a function changeDataForTest (only a function for testing the event), which should change the data displayed in Text.
But if I click on this, it isn't changed. The value of the displayed string only changes, if i add (context as Element).reassemble(); after calling the method. Is this the normal way to go, or is there a smoother way to solve my problem?
dynamic changeDataForTest(neuerWert) {
this.data = neuerWert;
}
Column(
children: [
Center(
child: Text(
this.data + this.wiegehts,
),
),
FlatButton(
textColor: Color(0xFF6200EE),
onPressed: () {
changeDataForTest('neuerWert');
(context as Element).reassemble();
},
)
],
)
Thanks
Lukas
If you're using only a small widget, you could use a StatefulWidget using the method:
setState(() {
// change your variable
})
If your widget is complex and has lots of different possible variables, I'll not recommend using setState as this method calls the build method every time is being used.
One simple and fast option, is to use ValueNotifier:
final myVariable = ValueNotifier(false); // where you can replace 'false' with any Object
and then, using it this way:
ValueListenableBuilder(
valueListenable: myVariable,
builder: (context, value, child) {
return Text(value); // or any other use of Widgets
},
);
myVariable.value = true; // if you're looking for to change the current value
finally, if you logic is truly complex and you need to scale, I'll recommend to use a StateManagement library like:
Provider
Riverpod
BloC
Others
You can find those libraries and examples over: https://pub.dev

Flutter: how to access context from Dismissible onDismissed

I'm trying to implement undo for a Dismissible list item in Flutter, and having problems accessing a BuildContext.
I have a flutter list, where each item is a card. The card is wrapped in a Dismissible, which allows the user to swipe to dismiss the card. Dismissible automatically removes the item from the list. Dismissible also has an onDismissed event - I'm using this event to update the item in Redux state store (setting an isDismissed flag to true), then show a snackBar which contains an UNDO button.
This is where I'm running into problems. I want the UNDO button to restore the item, by dispatching another action to the Redux store to set isDismissed to false. To do this I need a context, from which to get the store dispatcher. However when I try with the below code, I get an error when clicking on UNDO:
Looking up a deactivated widget's ancestor is unsafe
class ProductCard extends StatelessWidget {
final Product product;
const ProductCard(this.product);
#override
Widget build(BuildContext context) {
return Dismissible(
key: Key(product.id.toString()),
onDismissed: (direction) {
StoreProvider.of<AppState>(context).dispatch(DismissAction(product));
// Then show a snackbar to allow undo
Scaffold.of(context).showSnackBar(
SnackBar(
content: Row(
children: <Widget>[
Expanded(child: Text("Dismissed ${product.title}"),),
FlatButton(
onPressed: () {
// THIS IS WHERE I GET THE ERROR
StoreProvider.of<AppState>(context).dispatch(UndoDismissAction(product));
},
child: Text("UNDO"),
)
],
)
)
);
},
child: Card(
child: ...
)
);
}
}
From what I've read, I think what is going on is that the line StoreProvider.of<AppState>(context) inside the undo button's onPressed action is trying to use a context which belongs to the Card, but because the card has been removed from the list, it no longer exists.
I'm not sure how to do work around this. I've read about flutter keys, and think the answer may be to start passing around some kind of global key, but I can't quite get my head around how that works. I gave it a go and ran into another problem with 'inheritFromWidgetOfExactType' was called on null. Are keys the solution to this problem? If so where do I create the key, do I pass it in to the widget, what type of key should I use etc, or is there a better solution?
Many thanks!
Extract a single copy of the store into a local variable, which will then get captured by all the lambdas below.
#override
Widget build(BuildContext context) {
var store = StoreProvider.of<AppState>(context);
return Dismissible(
...
store.dispatch(DismissAction(product));

IconButton calling setState during onPressed shows no ripple effect

During the onPressed of my IconButton I need to update the database and then the UI so that the user sees feedback of the data change. To do this I call setState, which successfully lets the Widget rebuild. The problem is I'm no longer seeing the touch feedback ripple effect because the Widget rebuilds immediately.
var button = new IconButton(
icon: new Icon(isMyBoolTrue ? Icons.undo : Icons.event_available),
onPressed: () => setState(() => toggleDatabaseBool)
);
The issue was I was creating an ObjectKey with an object that was re-created every time during build. Solved the issue by using ObjectKey and the id field of my object instead of the object itself.
Bad
var card = new Card(
key: new ObjectKey(goal), //the goal object was re-created during `build`
child: button
);
Good
var card = new Card(
key: new ObjectKey(goal.id), // need to key off of the id field as it remains constant
child: button
);
That shouldn't stop the splash. The only reason the splash should stop is if you add or remove one of the widgets between the IconButton and the Material, or change its key, or change the Material's key, or move the Material in the tree. (Some of those are bugs in the framework right now, I hope to fix them in the coming months.)
Can you post a minimal app that shows the problem?
Meanwhile, we're tracking the issue at https://github.com/flutter/flutter/issues/6751 and https://github.com/flutter/flutter/issues/5456