Why are stateful widgets defined as two classes in flutter?
GenericsDartFlutterGenerics Problem Overview
I'm new to flutter/dart, so while I try to make an app I also try to understand why things are a certain way. In the flutter docs there is example code of a stateful widget as shown:
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));
}
}
Questions:
-
Why are they defined with two classes as opposed to one? I'm guessing the State class can be used somewhere else so it was better to be split up.
-
From what I understand the
createState()
function returns an object of typeState
, so having_YellowBirdState extends State
makes sense, but why isYellowBird
passed into the generic class ofState
? My guess it has something to do withYellowbird
extending theStatefulWidget
class but not quite sure.
Generics Solutions
Solution 1 - Generics
There are multiple reasons :
-
Widgets are immutable. Since
StatefulWidget
extendsWidget
it therefore must be immutable too. Splitting the declaration into two classes allows bothStatefulWidget
to be immutable andState
to be mutable. -
Widgets are instantiated using the syntax
new MyWidget()
. If we merged both classes into one,new MyWidget()
would reset all the properties of the state every time its parent update.
As for the explanation of class _MyStatefulState extends State<MyStateful>
That is because the State
class can access to it's Stateful
part using the this.widget
field.
The generic is here to make that field of type MyStateful
instead of just StatefulWidget
. As you may want to access MyStateful
properties.
Solution 2 - Generics
-
One of the main design decisions of Flutter is that it is cheap to re-create Widgets, so
build()
can be called to rebuild a branch of the widget tree when something changes. This works fine for stateless widgets which are given their immutable values through the constructor. But stateful widgets need to preserve their state across builds. In your example, the framework can create multipleYellowBird
s, but it only ever creates oneYellowBirdState
. Each newly createdYellowBird
gets transparently hooked up to the existingYellowBirdState
by the framework. -
A subclass of
State
needs to know its Widget type so that the compiler knows what type the variablewidget
is. InYellowBirdState
you can refer to the Widget withwidget
. IfYellowBird
had a member variablefinal String foo
, the compiler knows thatwidget.foo
is the String called foo inYellowBird
.
Solution 3 - Generics
The Flutter documentation explains this.
> Having separate state and widget objects lets other widgets treat both stateless and stateful widgets in exactly the same way, without being concerned about losing state. Instead of needing to hold on to a child to preserve its state, the parent can create a new instance of the child at any time without losing the child’s persistent state. The framework does all the work of finding and reusing existing state objects when appropriate.
Basically, its so that a Stateful Widget can be re-instantiated (whenever its build()
, e.g. from a state change) without losing its state.
This is also enforced by Widgets being immutable, so the mutable state data must be stored elsewhere: the State
object.
Solution 4 - Generics
class YellowBird extends StatefulWidget
StatefulWidget is an immutable class (Immutable class means that once an object is created, we cannot change its values).
- The class must be declared as final (So that child classes can’t be created).
- Data members in the class must be declared as final. (So that we can’t change the value of it after object creation).
- A parameterized constructor.
- Getter method for all the variables in it. No setters (To not have the option to change the value of the instance variable).
class _YellowBirdState extends State<YellowBird>
State
Same as this StatefulWidget class which is immutable is calling a function of createState()
which define the class State
of the widget after its called in a flutter
so we can change the values of the widget again and again by this approach but we cannot change the type of Stateful or Stateless.