Why build method isn't defined inside StatefulWidget? - flutter

I'm currently learning Flutter. I tried to deep dive into Flutter Widget life-cycle, and I wonder why StatefulWidget are written like this :
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
// initState
// setState
// ...
#override
Widget build(BuildContext build) {
...
}
}
but not :
class Example extends StatefulWidget {
// initState
// setState
// ...
#override
Widget build(BuildContext build) {
...
}
}
I think the latter makes the source simple. But I don't know why they're using the former style ?

The reason why StatefulWidget uses a separate State class and not having build method inside its body is because all fields inside a Widget are immutable, and this includes all its sub-classes.
You might have noticed that StatelessWidget has its build and other associated methods defined inside it, but that was possible due to the nature of StatelessWidget which is rendered completely using the provided info, and doesn't expect any future change in its State.
In the case of StatefulWidget, State information occasionally change (or expected to change) during the course of the app, thus this information isn't suitable for storage in a final field (build) to satisfy Widget class conditions (all fields are immutable). That's why State class is introduced. You just have to override the createState function to attach your defined State to your StatefulWidget, and let all that change happens in a separate class.

Related

createState function creates a mutable state in Flutter

createState:
Creates the mutable state for this widget at a given location in the tree.
https://api.flutter.dev/flutter/widgets/StatefulWidget/createState.html
Now, in code:
class A extends StatefulWidget {
#override
_AState createState() => _AState();
}
class _AState extends State<A> {
}
Here we create a separate class named _AState which inherits from a predefined class named State?
So, what is createState' role here? How does it create a mutable state for us?
With createState you tell the StatefulWidget which class to use as state for this widget. And you tell it here that it needs to create an instance of _AState for this widget.
By the way, it is also recommended to write it as
State<A> createState() => _AState();
It still works the way you wrote it but the IDE might complain about
Avoid using private types in public APIs
Saying the return type is State<A> instead of _AState removes this warning.
In order to create a stateful widget in a flutter, it uses the createState() method. Stateful Widget means a widget that has a mutable state.

Assigning InheritedWidget in build-Method

Let A be an InheritedWidget, that I can get throughout the whole app by calling A.of(context).
If I have a StatefulWidget, what is the better option (in terms of performance or code quality):
A)
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
A a;
#override
Widget build(BuildContext context) {
a ??= A.of(context);
return Container();
}
}
B)
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
#override
Widget build(BuildContext context) {
final a = A.of(context);
return Container();
}
}
I have never seen someone using Option A), so I am wondering. I prefer Option A) because every method in the _TestState class can use the a-Object easily and it is also assigned only once in the build method.
Option B is likely enough if you keep widgets small. It won't be great if you have many methods that depend on the inherited widget.
Reading option A brings up questions in my mind like
"You're caching A, do you care if A changes up in the tree?"
"Is A needed outside of build?"
"If so, why? Do we know it will be initialized at that point?"
"If not, why is it an instance field?"
Both options work though.
In terms of code quality a third option is to apply the dependency inversion principle by making A a parameter to the widget.
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({#required this.a});
final A a;
...
}
Then callers can create it with MyStatefulWidget(a: A.of(context)). This reads better than option A, though, granted, they're not equivalent.
I'm not aware of performance differences considerable enough to discuss here.

What is the difference between StatefullWidget and StatelessWidget regards to Performance?

Is there a Performance impact if we just use StatefullWidget over the StatelessWidget it vice-versa?
In my point of view, we just use StatefullWidget for things like update part of the UI using setState(), have a way to setup some code in the initState() and dispose things in the dispose() function. So when I don't need those things I go ahead and use StatelessWidget.
But what is the real performance impact between these two most used widgets?
Performance-wise, a StatelessWidget is almost identical to a StatefulWidget with an empty State.
Writing:
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
or:
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
#override
Widget build(BuildContext context) {
return Container();
}
}
won't have any visible impact on the performance of your app.
There indeed is a small gain when using StatelessWidget here. But it's ridiculously small:
The difference between them can be summarized as calling an empty function vs not calling it. It's something, but absolutely doesn't matter.
The reason being, internally the implementation of StatefulWidget and StatelessWidget is almost the same.
StatelessWidget does have all the extra life-cycles that StatefulWidget possess.
It has an "initState"/"dispose". Even a setState!
They are just not part of the public API.
What is a StatelessWidget?
A widget that does not require mutable state.
Performance considerations
The build method of a stateless widget is typically only called in three situations: the first time the widget is inserted in the tree, when the widget's parent changes its configuration, and when an InheritedWidget it depends on changes.
Sample Code
class MyWidget extends StatelessWidget {
const MyWidget ({ Key key }) : super(key: key);
#override
Widget build(BuildContext context) {
return new Container(color: const Color(0xFF00BD3A));
}
}
What is a StatefulWidget?
A widget that has mutable state.
Performance considerations
here are two primary categories of StatefulWidgets.
The first is one which allocates resources in State.initState and disposes of them in State.dispose, but which does not depend on InheritedWidgets or call State.setState. Such widgets are commonly used at the root of an application or page, and communicate with subwidgets via ChangeNotifiers, Streams, or other such objects. Stateful widgets following such a pattern are relatively cheap (in terms of CPU and GPU cycles), because they are built once then never update. They can, therefore, have somewhat complicated and deep build methods.
The second category is widgets that use State.setState or depend on InheritedWidgets. These will typically rebuild many times during the application's lifetime, and it is therefore important to minimize the impact of rebuilding such a widget. (They may also use State.initState or State.didChangeDependencies and allocate resources, but the important part is that they rebuild.)
Sample code
class YellowBird extends StatefulWidget {
const YellowBird({ Key key }) : super(key: key);
#override
_YellowBirdState createState() => new _YellowBirdState();
}
class _YellowBirdState extends State<YellowBird> {
#override
Widget build(BuildContext context) {
return new Container(color: const Color(0xFFFFE306));
}
}
Full Explanaton is given here

Access member of State from instance of Stateful Widget

I have StatefulWidget instance.
However I want to access the method of State from the instance of StatefulWidget.
It might be very simple and basic for flutter, but for the beginner of Stateful/State systen, it is a bit complex.
class MainBody extends StatefulWidget{
#override
_MainBodyState createState() => _MainBodyState();
}
class _MainBodyState extends State<MainBody>{
_MainBodyState();
void connectMainBody(){
print("ConnectMainBody");
}
class _MyHomePageState extends State<MyHomePage> {
Widget mainBody;
#override
void initState() {
super.initState();
mainBody = new MainBody();
mainBody.connectMainBody()// how can I access this method??
}
My idea was completely wrong.
https://medium.com/flutter-community/flutter-communication-between-widgets-f5590230df1e
I checked this page and learned.
How to access from Parent to Child.
By giving parameters to Child's Constructor.
How to access from Child to Parent.
By using callback function given to Child from Parent in advance.
I think I should learn about GlobalKey next.
Thank you very much for your advice.

How to persist bloc instance in widget tree

I'm using an InheritedWidget to expose a bloc class to child components. However, every time the widget tree gets recreated, a new instance of the bloc class is instantiated. As I'm using BehaviourSubject classes to store the latest values of some textfields, I'm loosing the current values with every recreation. How could this be solved, i.e. the bloc class should only be instantiated once.
It depends on how your provider were made, if it's an a extension of StatefulWidget with an a InheritedWidget.
If it's only extends from a InheritedWigdet, you'll miss the dispose method because it doesn't extends from StatefulBuilder, but, will never instantiate again, and the dispose method will be when you'll close your application. Check this example:
class Provider extends InheritedWidget {
Provider({Key key, Widget child}) : super(key: key, child: child);
final AppBloc bloc = AppBloc();
static AppBloc of(BuildContext context) =>
(context.inheritFromWidgetOfExactType(Provider) as Provider).bloc;
#override
bool updateShouldNotify(Provider oldWidget) => true;
}
This AppBloc is a component that has all my applcation's blocs.
But, if your provider extends an a StatefulWidget with a InheritedWidget, you can pass your bloc as a constructor parameter in the class you want, and this class should be Stateful too, so you can pass in the initState and will be rebuilted only when you access it again.
If you are using a StatefulWidget then you can instantiate the bloc in the initState method.