[MUSIC PLAYING]
ANDREW BROGDON: Hey, everybody.
I'm Andrew from the Flutter team.
And in this video, I'm going to tell you
all about Flutter's stateful widgets--
what makes them different from stateless widgets,
how state objects work, and more.
This is actually the second in a run of videos we're doing.
So if you haven't seen the first one,
I recommend scrolling down to the video description
below, where we have a link to it.
If you have seen that first video,
you're probably pretty familiar with stateless widgets.
They're an immutable configuration, or blueprint, so
to speak, for an element, which is what's
actually placed on screen.
Now, if you're like me, you hear that and you think,
immutable configs are great, but I'm not
writing an app that's just going to draw itself and stop.
What about data that changes?
How do I track that and update my UI?
Well, that's where stateful widget comes in.
It provides immutable configuration info
and a state object that can change over time and trigger
rebuilds of the UI.
Let's take a look at some code, and I'll show you how it works.
Here's a basic stateless widget.
It takes a name and count in its constructor,
and it builds a text widget to display them.
Super simple.
But let's say I need that count to change over time.
I can't change anything inside a stateless widget, right?
Count is final.
So I'll turn this into a stateful widget.
Now I've got a couple classes, a widget and a state object.
The widget is responsible for two things--
holding onto that immutable name value, which won't change,
and creating the state object.
The state object, for its part, holds
the count value, which you'll notice
is no longer tagged as final.
It can change, and the state object now
builds child widgets.
In this case, the text widget that
will display the name and count.
To get a handle on how this really works,
let's take a look at the widget and element trees.
If you recall from our previous video,
it's the element tree that actually
represents what's on screen.
The widgets are just blueprints for those elements.
Now, for stateless widgets, the process of getting on screen
is pretty straightforward.
You give Flutter a stateless widget, and Flutter says,
no problem, I can display this.
I just need an element.
Hey, widget, can you make an element for me?
The stateless widget creates a stateless element,
and it's mounted into the element tree.
If that stateless widget has child widgets that it builds,
elements are made from them, they
get mounted, and so on down.
With a stateful widget, there's an extra step.
Just like before, first comes the widget.
But when Flutter asks it to create an element,
it returns a stateful element.
That stateful element then goes back to the widget
and says, hey, can you make a state object for me?
Which is what that createState method is for.
That method kicks out a new state object,
and the element holds onto it.
Now it's time to build child widgets,
so stateful element calls the state object's Build method.
If we take a look at the code from before, you'll see why.
In order to build a text with the correct string,
we need the name property from the widget and the count
property from the state object.
Because the state object maintains a reference
to the widget for widgets maintaining state,
it can access both values and use them
to construct the text widget.
And there it is.
Text is stateless, so it creates a stateless element
which gets mounted in the tree.
Now, technically, text has a few children of its own
to help with accessibility and actually rendering the text,
but for this example I'm just going to keep things simple
and stop right here.
So everything's built, and our element tree is ready to go.
All right, let's take another look at the state object.
Right now, nothing in here is actually updating the state.
Nothing's changing that count property.
But if I drop in a gesture detector,
I can use the setState method in the state object
to make a change.
setState is a way for you to set properties on the state object
and trigger updates to the UI.
You give it a function that makes the changes,
and the state object runs it and make
sure the UI gets rebuilt afterwards.
If we go back to the diagram, when setState runs,
the count gets incremented.
Plus-- and here's the important bit--
the state object marks its element as dirty,
meaning it will rebuild its children on the next frame.
And here, I'm using frame in the graphics card,
60-frames-per-second sense.
When that next frame rolls around,
just like before, stateful element
calls the Build method in the state
object to rebuild the children, and out pops a new text widget
that shows the new count.
The old text widget goes away, and in comes the new one.
And here's a cool part.
Because that new widget is the same type as the old one--
they're both text-- the stateless element stays right
where it is, and just updates itself
to reference the new widget.
So that's a basic example of how state objects can
hold data that changes over time and rebuild child widgets when
it does.
But there's another really useful thing
about state objects--
they have a long lifespan.
They can remain attached to the element tree
even when the original widget gets replaced by a new one,
as long as that new one is of the same type.
For example, if the ItemCounter widget itself
would rebuild, maybe from a change above it in the tree,
the original ItemCounter widget goes away,
but since the new one is the same type of widget,
the stateful element and state object
stay right where they are.
They survive the change in widgets,
and just mark themselves dirty so their children get
rebuilt. Then the state object's Build method kicks out
a new text widget using its count value,
but with the new ItemCounter widget's name value.
The old text widget goes away, the new one's mounted,
and the stateless element for the text
stays right where it is.
So that's how state can be maintained
even after the widget that made the state object
has been replaced.
It's kind of like stateful hot reload, right?
You can push new code to your device
without changing where you are in the app and what's going on.
Here, we're building new widgets with new properties,
but that state stays the same.
I'm not using it in this example,
but there's even a method in the State class
called didUpdateWidget that you can override
if your state object needs to know
when its widget gets replaced.
Animated Container, for example, uses
this to know when it should start animating the change
from one config to another.
So as you can see, stateful widgets
give you the power to track data over time
and update your app's UI to match, which is really handy.
The ironic thing is, though, as you get better and better
with Flutter, you'll probably find
yourself writing fewer and fewer stateful widgets.
One of the reasons is that a lot of the common use cases
have already been implemented.
For example, say you have a stream of data,
and you want a stateful widget that rebuilds whenever
the stream emits a new value.
Well, that's a stream builder, and it's
part of the Flutter framework.
Another reason is that if you've got
a bunch of nested stateful widgets,
passing data through all those build methods and constructors
can get cumbersome.
Fortunately, there's another type of widget
that makes it easy to access data stored
near the top of the tree even if you're 100 widgets down.
It's called InheritedWidget, and we'll tell you all about it
in the next video in the series.
In the meantime, for more information
about Flutter and all its many widgets, head to flutter.io.
[MUSIC PLAYING]