How does SetState() decide whether a widget needs rebuilding? - flutter

I'm trying to wrap my head around the concept of state, the setState function, and rebuilding stateful widgets. Would this code (inside a method)
setState(() {
newText="some new text";
});
behave any differently from
newText="some new text";
setState(() {});
In other words, does setState(){} only concern itself with what's inside itself, or does it pay attention to state changes anywhere inside its parent widget (or even higher than its parent on the widget tree)?

The setState((){}) rebuilds the current widget state i.e it just calls the build method if you have updated any value inside the setState((){}) or have updated before calling the setState((){}), it will behave same.
For some values which have been initialised or defined inside the build method it will not take any effect, because the setState((){}) just rebuilds the Build() method.
In your case both the setState((){}) calls will behave the same as you have already updated your required value before rebuilding the state. The setState((){}) also updates the values which are dependent on the updated variable from setState((){}) i.e depends upon the variable value which you are updating in setState((){}).
Checkout this interactivity tutorial by flutter for uses
For the setState((){}) method uses checkout this

Related

What is the difference between setState and GetX in flutter?

I am just looking forward to understanding the difference between using a normal setState(() {}) and the update() method of the Getx package.
As much as I can see from the practical point of view when setState(() {]) is used the whole page is rebuilt but when GetX has used only the part of .obs is rebuilt. What I want to understand is more in-depth difference.
setState will refresh the whole widget. But using the Getx you can refresh the particular widget.
More you can find from this link : Getx Controller
Getx's state manager, is a tool that let you control and manage your widget state from a separate place, which is the GetxController.
The Getx state management widgets, like GetBuilder(), Getx(), Obx()... are StatfulWidgets and under the hood, they also use a normal SetState(() {}), but the implementation of calling them is really different than a usual setState(() {}) call.
As example, the GetBuilder() :
class GetBuilder<T extends GetxController> extends StatefulWidget {
final GetControllerBuilder<T> builder;
final bool global;
final Object? id;
final String? tag;
final bool autoRemove;
final bool assignId;
final Object Function(T value)?
/*...*/
and under the hood, it updates the state by getting a method like this :
void getUpdate() {
if (mounted) setState(() {});
}
then store it in Map we call it from the controller with an update().
Your sentence:
As much as I can see from a practical point of view when setState is used the whole page is rebuilt but when GetX has used only the part of .obs is rebuilt
is wrong!
Try wrapping your whole page with a GetBuilder and call the update() from its controller, and you will have a full rebuild for the whole page because it's just a normal StatefulWidget that will be rebuilt by calling its build() method again and again...
You face the whole page state update because you wrap the whole of it with a StatfulWidget, the same thing with GetBuilder(), Obx()...
There is a Flutter builder widget that let you also manage the state of its child just locally, which is StatefulBuilder, give it a quick check and I recommend that you play with it to understand that approach of using a builder widget to update the state.
Besides that Getx gives you the ability to separate your logic and state management into the GetxController, it let you control which widget to update exactly with its own custom mechanisms like using the update() method ( which calls a normal SetState(() {}) ) with a specific id, like this:
update([id1, id2, id3]);
Under the hood search over a Map where it stores all the SetState(() {}) that it got from the Getx's GetBuilder(), then look for what matches that id, then call only what belongs to it, and this what causes that widget having one of those id will be updated, and other widgets will not.
you can check more about how Getx works with a quick reads of its source code, I guess it will be very helpful for you.

Flutter Provider reinitialize model

I use MultiProvider and then create all my models. Lazy loading is enabled and as such when I open my page widget the constructor of my model is called when I call Provider.of<>(context).
This initialize my model and the model gets fresh data.
I have the following issue however, when I pop the view(widget) and revisit the view(widget) later, Provider.of<>(context) is called again, but since the model was already initialized I get the previous data from the model (This is useful because I do use this to preserve state between certain screens).
I need my model to reinitialize since I need to refresh my data and reset the page values, and since the constructor is never called again, I don't get any of these.
No matter what I do, if I call the initialize method from initState() / didChangeDependencies() it always error since I'm changing the data while the widget is building.
I'm looking for something like the following:
MyChangeNotifier variable = MyChangeNotifier();
ChangeNotifierProvider.value(
value: variable,
child: child()
)
To reinitialize my class, but from what I read this is bad and don't know where to call it.
I have no idea how to proceed and any help would be appreciated.
So I found what I was looking for in the Provider actual documentation here.
The key is to call your code that would update the UI or trigger a rebuild inside a Future.microTask(). This will only then trigger the rebuild once the future completes and not trigger the rebuild while the widget tree is still building.
#override
initState() {
super.initState();
Future.microtask(() =>
context.read<MyNotifier>(context).getMyData(); // Or in my situation initialize the page.
);
}

When to use Provider.of<X> vs. Consumer<X> in Flutter

I'm still wrapping my head around state-management techniques in flutter and am a bit confused about when and why to use Provider.of<X> vs. Consumer<X>. I understand (I think) from the documentation that when choosing between these two you would use Provider.of when we want access to the data, but you don't need the UI to change. So the following (taken from the docs) gets access to the data and updates the UI on new events:
return HumongousWidget(
// ...
child: AnotherMonstrousWidget(// <- This widget will rebuild on new data events
// ...
child: Consumer<CartModel>(
builder: (context, cart, child) {
return Text('Total price: ${cart.totalPrice}');
},
),
),
);
Whereas, where we only need the data on don't want to rebuild with UI, we'd use Provider.of<X> with the listen parameter set to false, as below:
Provider.of<CartModel>(context, listen: false).add(item); \\Widget won't rebuild
However, listen isn't required and so the following will run too:
Provider.of<CartModel>(context).add(item); \\listener optional
So this brings me to a few questions:
Is this the correct way to distinguish Provider.of<X> and Consumer<X>. Former doesn't update UI, latter does?
If listen isn't set to false will the widget be rebuilt by default or not rebuilt? What if listen is set to true?
Why have Provider.of with the option to rebuild the UI at all when we have Consumer?
It doesn't matter. But to explain things rapidly:
Provider.of is the only way to obtain and listen to an object.
Consumer, Selector, and all the *ProxyProvider calls Provider.of to work.
Provider.of vs Consumer is a matter of personal preference. But there's a few arguments for both
Provider.of
can be called in all the widgets lifecycle, including click handlers and didChangeDependencies
doesn't increase the indentation
Consumer
allows more granular widgets rebuilds
solves most BuildContext misuse
Provider.of<>
applying provider, whole widget will rebuild if listen true.
Consumer<>
using consumer only specifically allowed widget will rebuild.
For your questions:
Is this the correct way to distinguish Provider.of<X> and Consumer<X>. Former doesn't update UI, latter does?
Provider.of<X> depends on value of listen to trigger a new State.build to widgets and State.didChangeDependencies for StatefulWidget.
Consumer<X> always update UI, as it uses Provider.of<T>(context), where listen is true. See full source here.
If listen isn't set to false will the widget be rebuilt by default or not rebuilt? What if listen is set to true?
Default value is true, means will trigger a new State.build to widgets and State.didChangeDependencies for StatefulWidget. See full source here.
static T of<T>(BuildContext context, {bool listen = true}).
Why have Provider.of with the option to rebuild the UI at all when we have Consumer?
Pretty much covered by Rémi Rousselet's answer.
There should not be any performance concern by using it, moreover, we should use consumers if we want to change some specific widget only on screen. This is the best approach I can say in terms of coding practice.
return Container(
// ...
child: Consumer<PersonModel>(
builder: (context, person, child) {
return Text('Name: ${person.name}');
},
),
);
Like in the above example, we are only required to update the value of the Single Text Widget so add consumers there instead of Provider which is accessible to other widgets as well.
Note: Consumer or Provider update the only reference of your instance which widgets are using, if some widgets are not using then it will not re-drawn.
The widget Consumer doesn't do any fancy work. It just calls Provider.of in a new widget, and delegate its build implementation to [builder].
It's just syntactic sugar for Provider.of but the funny thing is I think Provider.of is simpler to use.
Look at this article for more clearance
https://blog.codemagic.io/flutter-tutorial-provider/
We have 3 things to understand here.
When you wrap Provider around a widget it sets up a reference to a widget tree and a variable whose changes you want to refer to.
using Provider.of(context) you can get access to the variable you want to monitor and make changes in it.
Provider.of(context) with and without listen gives you a reference to the above-declared Provider object and a widget tree where it can be accessed from. But as said by others, it rebuild the whole widget tree it sits on top of when listen is not false.
In the end, you can use consumer to monitor any changes that happened using the above step
The consumer acts like a more granular listener and be applied to a fixed widget to help avoid unnecessary rebuilds.
it's just a personal preference and depends on how you understand and use provider.
so the way i think of provider is it's just an object that is providing a ChangeNotifier Object that has Code and Data down the widget Tree.
So,I use :
Consumer<T>
When i want to listen to changes in Data and update/rebuild my UI according to those changes.
Provider.of<T>
When i just want to call the Code. with the listen parameter set to false.
if your problem is to know what the difference is, here is a track
Consumer
reload consumer-only child widgets
Provider.of (with listen true)
reload from the last buildcontext found in the tree
actually in a simple example
exemple1 provider.of
in exemple1 when I click on my container, his increase his size ( gesturedetector send a newvalue at h variable , h variable is in function named method in provider)
with 'provider.of' flutter rebuild at the first Buildcontext below #override
that mean the totality of tree are rebuild
exemple2 consumer
in exemple2 when I click on my container, his increase his size ( gesturedetector send a newvalue at h variable , h variable is in function named method in provider)but with consumer only sélectionned widget are rebuild
that mean one widget are rebuild the other widget doesn't "move"
I hope I could help you

setState() vs notifyListeners(), which one is more efficient?

I always aim to make my widgets Stateless instead Stateful for performance benefits. In some cases(updating the BottomNavigationBar index e.g.) notifyListeners() can provide identical functionality of the setState().
At first, I think notifyListener() is lower level, more fundemantal function comparing to setState(), so it should be more efficient. Because setState() method may triggers too many higher level framework methods, so it may spends more CPU power.
But it's hard to be sure without making a proper and detailed performance testing. So what is the answer?
Edit: Also, in some cases, notifyListeners() behaves exactly like setState(). For example, I have Text widget inside a StatelessWidget that holds a Random value and when I notify the an unrelated value inside the Class, the Text widget is also getting update. So, what is the difference?
Assuming that you're comparing ChangeNotifier.notifyListener with State.setState to rebuild the widget tree, then:
setState will always win.
The reason, notifyListener rebuilds your widget tree because it causes setState itself.
For notifyListener to work, there's usually a StatefulWidget somewhere in your tree that does the following:
class MyState extends State<T> {
ChangeNotifier notifier;
initState() {
notifier.addListener(() => setState(() {}));
}
}
In any case, this probably doesn't matter.

flutter initState() vs build()?

I am confused about when to put my code in initState() compared to build() in a stateful widget. I am doing a quiz on flutter's udacity course which has this todo item, which was to move a block of code from build() to initState(). But I don't know the purpose or advantage of doing that. Why not just put all the code in build()?
Is it that build() is called only once while initState() is called on every state change?
Thank you.
This is actually the opposite.
build can be called again in many situations. Such as state change or parent rebuild.
While initState is called only one time.
build should be used only for layout. While initState is usually used for variable initialization.
It's in the comment within the build state of the link you provided.
Widget build(BuildContext context) {
// TODO: Instead of re-creating a list of Categories in every build(),
// save this as a variable inside the State object and create
// the list at initialization (in initState()).
// This way, you also don't have to pass in the list of categories to
// _buildCategoryWidgets()
final categories = <Category>[];
...
Creating Categories List in the Build State will lead to the list being created on every build. This is necessary since you only want it to be created once, so the best place to do this is in initState() since it will only be called once when the state object is created, Thereby eliminating the cost of re-creating the categories on each build.
According to flutter doc:
InitState
Called when this object is inserted into the tree.
The framework will call this method exactly once for each State object it creates.
Override this method to perform initialization that depends on the location at which this object was inserted into the tree (i.e., context) or on the widget used to configure this object (i.e., widget)
build
The framework calls this method in a number of different situations:
After calling initState.
After calling didUpdateWidget.
After receiving a call to setState.
After a dependency of this State object changes (e.g., an InheritedWidget referenced by the previous build changes).