flutter initState() vs build()? - flutter

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).

Related

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.
);
}

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

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

How does `build` occur from root to leaves in Flutter?

I've tried tracing through the source to answer this but I get a little lost in the Flutter machinery. We pass runApp a Widget, which becomes the root widget of our app. That widget must implement build, which returns a Widget.
Does Flutter just use simple recursion to call build on that returned Widget, and so on, for the Widget returned by each subsequent child's build method?
While recursing, and it encounters a StatelessWidget, does Flutter do a type check to call createState instead of build, and then perform an extra step, calling build on the State that createState returns?
How does the recursive / chain of calls to build methods stop? For example, the Text widget has a build method that returns a RichText widget, which is a MultiChildRenderObjectWidget. Does Flutter again do type checking here and stop calling build and instead invoke createElement, which in the end generates the elements for the Element tree?
It is more complex than a simple recursion.
You can read more about the build and render process of a widget here
https://api.flutter.dev/flutter/widgets/WidgetsBinding/drawFrame.html
While the widgets are inmutable, Elements are the instantiation of them. So while StatelessWidgets and StatefulWidgets are recreated in each build, Elements are updated in the tree.
The StatefulWidget is managed by StatefulElement that keeps the state instance in its instance, so it persits while the StatefulWidget is rebuilt
The docs has a very good explanation of what is an Element too:
https://api.flutter.dev/flutter/widgets/Element-class.html

When is the State object destroyed in a StatefulWidget?

One of Flutter's mantras is that widgets are immutable and liable to be rebuilt at a moment's notice. One reason for the StatefulWidget is the accompanying State object, which 'hangs around' beyond any individual build() method call. This way text values, checkbox selections, can persist when the widgets themselves are being rebuilt.
However, when are the State objects themselves destroyed? Is it when their associated widget is removed from the widget tree? And under what circumstances does that happen exactly-- when a Navigator is used to go to a new widget? When you go to a different entry in a TabBar?
It's a little hazy to me, the scenarios in which widgets are actually removed from the widget tree and their associated state destroyed. What other circumstances do I need to be aware of that my State obejct is liable to vanish, so I can take appropriate measures with PageStorageKeys and whatnot?
The general answer is: When it's associated Element (the BuildContext object) is disposed after having been removed from the Element tree.
Note that an Element (and therefore a Widget) cannot remove itself from the tree.
It has to be its parent that removes it.
Most of the time, this happens depending on what the build method of its parent do.
There are two main scenarios:
The build method returned a different widget tree.
Typically going from:
return Foo();
To:
return Bar();
will destroy the state of Foo.
Note that this also happens when Foo "moved" :
return Foo();
To:
return Bar(child: Foo());
will still dispose the state of Foo.
The second scenario is when the Key change:
return Foo();
into:
return Foo(key: Key("foo")) ;
Or:
return Foo(key: Key("bar"));
into:
return Foo(key: Key("foo")) ;
Will both destroy the state of the previously created Foo.
on Dispose Methode
#override
dispose()

What does BuildContext do in Flutter?

What does BuildContext do, and what information do we get out of it?
https://docs.flutter.dev/flutter/widgets/BuildContext-class.html is just not clear.
https://flutter.dev/widgets-intro/#basic-widgets on the 9th instance of the term BuildContext there is an example, but it's not clear how it is being used. It's part of a much larger set of code that loses me, and so I am having a hard time understanding just what BuildContext is.
Can someone explain this in simple/very basic terms?
BuildContext is, like it's name is implying, the context in which a specific widget is built.
If you've ever done some React before, that context is kind of similar to React's context (but much smoother to use) ; with a few bonuses.
Generally speaking, there are 2 use cases for context :
Interact with your parents (get/post data mostly)
Once rendered on screen, get your screen size and position
The second point is kinda rare. On the other hand, the first point is used nearly everywhere.
For example, when you want to push a new route, you'll do Navigator.of(context).pushNamed('myRoute').
Notice the context here. It'll be used to get the closest instance of NavigatorState widget above in the tree. Then call the method pushNamed on that instance.
Cool, but when do I want to use it ?
BuildContext is really useful when you want to pass data downward without having to manually assign it to every widgets' configurations for example ; you'll want to access them everywhere. But you don't want to pass it on every single constructor.
You could potentially make a global or a singleton ; but then when confs change your widgets won't automatically rebuild.
In this case, you use InheritedWidget. With it you could potentially write the following :
class Configuration extends InheritedWidget {
final String myConf;
const Configuration({this.myConf, Widget child}): super(child: child);
#override
bool updateShouldNotify(Configuration oldWidget) {
return myConf != oldWidget.myConf;
}
}
And then, use it this way :
void main() {
runApp(
new Configuration(
myConf: "Hello world",
child: new MaterialApp(
// usual stuff here
),
),
);
}
Thanks to that, now everywhere inside your app, you can access these configs using the BuildContext. By doing
final configuration = context.inheritFromWidgetOfExactType(Configuration);
And even cooler is that all widgets who call inheritFromWidgetOfExactType(Configuration) will automatically rebuild when the configurations change.
Awesome right ?
what is the BuildContext object/context?
Before we knowing about BuildCotext, We have to know about the Element object.
What is Element object
(note: As a flutter developer we never worked with Element object, but we worked with an object(known as BuildContext object) that's similar to Element object)
The Element object is the build location of the current widget.
What's really mean by "build location" ?
when the framework builds a widget object by calling its constructor will correspondingly need to create an element object for that widget object.
And this element object represents the build location of that widget.
This element object has many useful instance methods.
Who uses the Element object and its methods ?
They are 02 parties that use the Element object and its methods.
Framework (To create RenderObject tree etc)
Developers (Like us)
What is BuildContext object ?
BuildContext objects are actually Element objects. The BuildContext interface is used to discourage direct manipulation of Element objects.
So BuildContext object = discouraged element object (That contains less number of instance methods compared to the original Element object)
Why framework discouraged the Element object and pass it to us ?
Because Element object has instance methods that must only be needed by the framework itself.
but what happens when we access these methods by us, It's something that should not be done.
So that the reason why framework discouraged the Element object and pass it to us
Ok Now let's talk about the topic
What does BuildContext object do in Flutter ?
BuildContext object has several useful methods to easily perform certain tasks that need to be done in the widget tree.
findAncestorWidgetOfExactType().
Returns the nearest ancestor widget of the given type T.
findAncestorStateOfType().
Returns the State object of the nearest ancestor StatefulWidget.
dependOnInheritedWidgetOfExactType().
Obtains the nearest widget of the given type T, which must be the type of a concrete InheritedWidget subclass, and registers this build context with that widget such that when that widget changes.
[Used by Provider package]
The above methods are mostly used instance methods of BuildContext object if you want to see all the methods of that BuildContext object visit this LINK + see #remi Rousselot's answer.