Using Riverpod for Flutter state, what's better: ConsumerWidget or just a Consumer where needed? - flutter

I'm fairly new to Riverpod but it seems that using a ConsumerWidget as the body of a screen is a bad practice because the screen is rebuilt when not needed.
For example:
the main widget (the screen itself) is a ConsumerWidget
somewhere in the hierarchy I have a list of clickable buttons, for which I'm watching a ChangeNotifierProvider to update a selected index (only one button can be clicked at a time).
It seems that whenever I click one button to update the index (and change the color of the button), the main widget's Build method is called, along with the items in my list.
However, when using just a Consumer widget inside the itemBuilder method of my ListView, clicking one button no longer triggers the build method of the main widget.
So, is it considered a good practice to just use Consumer widgets where needed?

Related

Should state practically be at the root of the tree (in most cases) in Flutter?

I'm utterly confused regarding the question of state management in Flutter.
So far I have read that the states of widgets have to be nested as deep in the tree as possible (or rather as close to the affected widget as possible) for better performance.
But what if such a nested state widget (InheritedWidget for example) has another state widget somewhere above it? Does the state widget at the lower level not loose it's state when the state widget higher in the tree requests rebuild for all of its descendants?
With this line of thought have I came to the conclusion, that state widgets just have to be at the root in the end, but I guess I'm wrong somehow.
The first part of your question is correct -
If a widget's state changes, this might require all its children to redraw.
But this is precisely why it is important to nest state as deep down in the widget tree as possible!
Assume the contrary, that all state information is stored at the root of the widget tree, at the very top.
Now if any information changes, no matter how small, it will lead to a complete traversal of the widget tree, rebuilding everything in the worst case.
And aside from the tree traversal, your application will also become very memory intensive. If all state is stored at the root, flutter can never tell when it is okay to release some information from memory. If the user leaves some views and the views are dismissed from memory, the information for them will still be stored at the top. And the only way to check wether that information is still needed would be to once again check the whole tree - very expensive!
All of this can be mitigated by putting your state as close as possible to the widget that will consume it. Because then
If the state changes, only a small subtree of the whole widget tree has to be traversed - This is fast.
If a widget is dismissed, flutter can also release all of the state information that has been stored for it. This frees memory.
yes ! every state widget has its own state and they are all independent. if the state of widget X is updated, only widget X will be updated
let suppose that you have an application that sows a family tree. in widget A you get the gradfather from an API, when you click on it you will be redirected to widget B where you can find his childrens, when you click on one of his childrens you go to widget C which shows the childrens of the selected father in widget B, now let's supposse that you want to add one children to this father.
you call the add-children endpoint. the problem here is that widget A will not be updated.
one solution to this, and to understand the state tree logic, is to pass a functionthat updates widget A from widget A to widget B and pass it from widget B to widget C and call it when an update happens either on widget B or C or even on A so widget A gets updated and you got the updated family tree in widget A
So basically flutter have it's own state management that is called setState(() {}) itu will update the state of the screen where setState is called if i have a button class widget in it's own file if i press the button i want to change the button name to something else so the setState will update the state or variables in the button class/widget.
Now how if the button wants to update a state/variables in the different class but in same screen? Since setState only update it's own class, so you to give the button onTap property with function constructer like this
final Function onButtonTap;
then put it on onTap like
onTap:() {
widget.onButtonTap();
}
Then in the screen where you want to update the state just call onButtonTap then use setState there

Why "this" changes also without a new class statefull widget screen instance?

I have a screen as statefull widget. When I instance it I have the same "this" in initState and build methods, as expected.
But if, from that screen, I open a new screen and than I come back to the first screen, first the statefull widget screen doesn't appear to be reinstanced, the method initState is not called again but the method build is called (as expected, the screen has to be drawed again) and it has a new "this" than the first time the screen has been displayed.
I could also accept the screen class has a new this but how is it possibile without a new instance of the screen widget?
It seems the class change its "this" without a new instance of the class.
Is it possibile? Why? Am I wrong?
By documents of flutter's stateful initstate
Called when this object is inserted into the tree.
The framework will call this method exactly once for each State object it creates.
Which means when you added the stateful widget for the first time this method is called and this (instance) is created..
Now the build method is called on various situations
The framework calls this method in a number of different situations. For example:
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).
After calling deactivate and then reinserting the State object into the tree at another location.
So each timethe build is called a new instance is created if you have added the code to create an instance in build method.
When you move to the next page the first screen is still in widget tree. Then you pop screen 2 so you see screen1 ahain but this time its not added to the widget tree so only the build is called.. if you do navigator.push from screen 2 and navigate to screen 1 you will see initstate being called again because a new instance of screen1 is added to the widget tree..

How to remove a widget from the screen without rebuilding the whole page in flutter

Lets say i have a button and a container , and i want the container to disappear when i press the button.
Without rebuilding a new page, is this possible ? or is rebuilding the whole page is better?.
It's not possible to do it without setState but rebuilding the entire view might not be necessary.
The scope of setState is the current widget so if you encapsulate just the controls involved in this operation in a separated widget, only this tree will be recreated and not the entire view.

How many setState() calls is overkill for Flutter?

I am new to Flutter and reactive programming is also new thing for me.
Let's say I want to build a timer with Flutter.
I add a Scaffold with all the necessary stuff in it and I add a IconButton which starts the Stopwatch and Text which displays elapsed time. I also add Timer.periodic to periodically (every 0.5 second) update the text.
Text Widget controls it's own state by checking if Stopwatch is running and updating it's values.
So now let's say I want to have more complicated logic that changes the text based on some actions with other buttons which are the siblings of Text. However it is not possible to call setState of Text widget directly from sibling widgets. As I understand the point of reactive paradigm is that the state can be passed down the Tree. However if I make my Scaffold as StatefulWidget and update the state of the parent every 0.5 second it will redraw my entire Scaffold with all it's children. So eventually when the Scaffold gets big enough it will have to update everything instead of single Text widget.
Am I correct? And is there any solution to this. I read something about Streams and Sinks however it looks very complicated and I think that there should be another solution.
You don't need to rebuild the whole tree, if the state only changed in a sub widget, ideally you want to call set state in that widget so only that part of the tree (the one whose state changed) is rebuilt.
Streams aren't really that complicated, it's a good way for you to send messages between different components in your app, which is what you're trying to do here.
In your case you can also use a ValueNotifier to store state in the parent widget, or maybe an AnimationController, and send its listener down to the sub widget that needs be updated on change.
In any case, the state is lifted to a parent widget, which then becomes accessible to the sub widget through a listener, or a stream. When the listener triggers a signal, you rebuild the sub widget only.
Extract out widget and call setState() form that widget and it's don't render all the widget again

Flutter: How to make a StatefulWidget to reinialize State on rebuild

Although I use a Scrollvier to explain the problem this applies to other StatefulWidgets.
When building a Widget tree like this
-StatefulWidget A
- Some StatelessWidgets (get completely rebuild)
-ScrollView (which is a Statefull widget)
The ScrollView keeps its State like the scroll position when SetState in "StatefulWidget A" is called which rebuilds the subtree.
This may be fine in many situations but is there a way that Stateful child widgets reinitialize on rebuild? Like make the ScrollView reset to its start?
Or alternatively is there a way to get informed when a StatefulWidget is rebuild so that I could reset the ScrollViews controller manually.