Should state practically be at the root of the tree (in most cases) in Flutter? - 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

Related

Why is context safe to be used inside didChangeDependencies() method but not inside the initState() method?

Both the initState() method and didChangeDependencies() are executed before the build() method of a state object, so why is the context not available inside initState() but available inside didChangeDependencies()?
According to the official docs, didChangeDependencies() is called whenever the dependency of the State object changes. What does dependency mean here, and when does it change? (I am a beginner, so please use layman's term to explain this concept to me. I looked up other similar questions, but was not able to understand this.)
Unrelated to this topic, I understand that flutter creates elements and renderObjects for each widget it encounters in the widget tree and if that widget is a statefulWidget, then a state object is also created and a reference to that state object is held inside the element. My question is when are the element, renderObject and state object associated with a widget completely removed from their corresponding trees? Does this happen when the widget is permanently removed from the widget tree, or are they kept even after the widget is removed from the widget tree and some other widget is displayed in its place? For example, let's say that I have a floating action button on my homepage and on clicking that I'm pushing a namedPage onto the stack using the pushNamed method of the Navigator class and displaying a new page. Let's say that the new page is a StatefulWidget which has a state object associated with it, so when I go back to my home page again using the back button, that StatefulWidget is removed from the widget tree, right? Are the State object, element and renderObject associated with that widget destroyed immediately, or does flutter keep them around? If flutter does keep them around for some time, then how does it decide when to destroy those objects?
Firstly, you have to understand what is BuildContext that usually name as context.
buildContext is: the place in the widget tree in which this widget is placed.
All widgets have a bool this.mounted property. It is turned true
when the buildContext is assigned. It is an error to call setState
when a widget is unmounted.
why unsafe to use context in initState is because the widget is unmounted. means that the widget doesn't have place in the widget tree.
didChangeDependencies(): This method is called immediately after initState on the first time the widget is built.
its safe now because property mounted is true.
for the 3rd, you may know about deactivate() method. here
this is another answer for full explanation of flutter widget lifecylce :Life cycle in flutter

Does Inherited Widget changes rebuild whole application when it's the parrent of MaterialApp?

I want to use InheritedWidget to access and change its data from anywhere in application.
I've read many articles about InheritedWidget, but I do not understand one of its behaviors.
Here it says that only widgets that are using InheritedWidget get rebuilt when data changes(which is exactly what I want).
But here it says that InheritedWidget is immutable and its data only changes when it is rebuilt itself!
So doesn't this make the whole widget tree below the InheritedWidget get rebuilt when the data changes?
How can I wrap the MaterialApp widget with InheritedWidget so I can change its data from anywhere in app and only rebuild a small Widget that is using InheritedWidget when the data changes?
I know I can implement this using provider package very easily, but in this part of application I want to use InheritedWidget if it's possible :)
An object or widget being immutable does not mean its values can't change.
You can declare a final List<widget> children, which is immutable since it is final, and still add and remove widgets from it. What is immutable is the reference.
When you use the InheritedWidget is the same. If a value changes it wont rebuild itself and all the tree below. Even it is actually changed and rebuilt, it does not necessarily rebuild all tree below, it'd happen only if the widget type or its child/children reference changed also.

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

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?

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.