To learn GetX I created a simple controller class:
class MyDataController extends GetxController {
RxString aString = ''.obs;
void updateString(String s) {
aString.value = s;
}
}
aString
's value is displayed in two classes: the AppBar
(not discussed here) and another class in which aString
is both set and displayed:
class Level1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
final MyDataController controller = Get.find();
final textController = TextEditingController();
return Column(
children: [
TextField(
controller: textController,
onChanged: (_) {
controller.updateString(textController.text);
},
),
Text(controller.aString.value),
],
);
}
}
I'm confused about which widgets need to be wrapped in an instance of Obx()
.
If I wrap only the Text()
(display widget) in an Obx
instance, it's updated when the TextField()
(input widget) changes. And if I wrap only the TextField()
widget in an Obx
instance, I get an error message:
The following message was thrown building Obx(has builder, dirty, state: _ObxState#019a0): [Get] the improper use of a GetX has been detected. You should only use GetX or Obx for the specific widget that will be updated. If you are seeing this error, you probably did not insert any observable variables into GetX/Obx or insert them outside the scope that GetX considers suitable for an update (example: GetX => HeavyWidget => variableObservable). If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.
Everything seems clear: widgets displaying state must be wrapped in Obx()
instances to display updated variables. That makes perfect sense. And widgets that change state don't need to be wrapped in Obx()
instances.
I'm confused, though, because if I wrap both widgets in separate Obx()
instances, I get the error message. But if I wrap the entire Column()
in an Obx()
instance, the text is properly updated when the TextField()
changes. ... What am I missing in my understanding?
You got it all up to the point when you wrapped the Text widget in an Obx. In actual fact it is best to wrap only the smallest widget that would need updating in Obx, the Text
widget in this case.
Let me explain what happened the cases in which you tried testing it out:
Case 1: When you wrapped only the Text
widget in Obx (The best thing to do)
This case happen to be the best and most encouraged approach. In this scenario when the value of aString changes in the controller (MyDataController) the Obx is notified to re-build only the affected Text
widget from scratch, and this is exactly the aim of GetX.
Case 2: When you wrapped both the Text
&& the TextField
widget in Obx (This will throw an error).
In this case you have wrapped both the Text
and TextField
widget in Obx, we can therefore let case 1 account for the Text
widget.
Now, moving unto the TextField
widget, an error will occur because the TexField
widget is not in any way dependent on any obs-value (observable value).
It is important to note that in the onChanged callback provided to the textField, the method updateString
called on the controller
have no effect whatsoever on TextField's parameter and thus this leads GetX to throw an error since you are trying to forcibly update/re-build a widget that needs no rebuilding.
Case 3: When you wrapped the whole column in Obx (Will not throw an error but not the best practice).
In this case the widget will be built with no error whatsoever since the Text
widget (which is inside the Column) is dependent on the value of aString
. So, let's see what happens when the method updateString
is called.
When the updateString
is called the whole Column is re-built (along with the TextField
and the Text
widgets and this action will as well cause the value in the Text
widget to be updated.
Now, you can see why this third case can be detrimental, if you try wrapping your whole app in Obx, your whole app will then have to get re-built (which can really affect your app's performance negatively. Of course GetX has a way of disallowing that and thus it throws an error when you try wrapping an HeavyWidget in Obx or GetX.