Take a tour of ten awesome state management techniques in Flutter. Learn how to control the flow of data when building complex large-scale mobile apps with RxDart, BLoC, and more https://fireship.io/lessons/flutter-state-management-guide/

1. StatefulWidget
2. StatefulBuilder
3. InheritedWidget
4. RxDart + BehaviorSubject
5.  BLoC
6. Redux
7. Mobx
8. Scoped Model
9. Flutter Hooks
10. Firebase

Flutter State Mgmt Guide https://flutter.dev/docs/development/data-and-backend/state-mgmt/intro
Bloc https://pub.dartlang.org/packages/flutter_bloc
RxDart https://pub.dartlang.org/packages/rxdart
2024-02-04T06:54:50.056Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
d6479152-97e8-4c8f-b5c4-3497be886409
d3a284a9011f9f98dfe2fe7ca7acfdd5e71bdf84a8e3829630921be947dcc44e
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
State management, for whatever reason, is a topic that brings out strong opinions and developers.
Oh.
Yeah.
Um, I'm gonna have To go ahead and sort of disagree with you there.
In today's video, we'll look at 10 different ways to build a basic counter app using different state management strategies in Flutter.
We'll also just talk about what state management is, and why there are so many different ways to approach it.
And hopefully by the end of this video, you'll know exactly which strategy is ideal for your If you're new here, like and subscribe, and you can grab a full source code on Fireship IO.
And, I'm giving away another t shirt with this video.
Just leave me a comment with your own opinions about state management Woah.
First of all, what is state?
In a reactive framework like Flutter, you can think of your UI as the return value of a function.
That function gets called with one argument, which is your state.
So state is just data that changes over the life cycle of your app.
A lot of your data can be self contained within a single widget.
That's known as Local State.
We'll look at the tools that we have built into Flutter to manage local state, which is pretty straightforward.
Things get interesting when we start talking about global state or state that needs to be shared throughout the widget tree.
Coming from the web development world, I've seen tons of debate over state management and a lot of apps over engineered with these big state management libraries that didn't really need them.
That's not to say they're not valuable, but even the creators and maintainers of those libraries will tell you that you probably don't need them.
We'll talk about the pros and cons of these various libraries as we go, but for now let's focus on the fundamental building blocks in Flutter, starting with the stateful widget.
When you run flutter create from the command line, it gives you some starter code that increments a counter with a stateful widget.
We're going to rebuild this counter multiple times throughout this video using different state management strategies.
To create a StatefulWidget, we need 2 classes.
The first one is the StatefulWidget itself and that implements a create state method.
And that returns our second class which is an extension of the State class.
And this is where all the heavy lifting happens.
1st, we define a property called counter, which is an integer that defines the actual data state of this widget.
Then we define a method called increment counter and it calls a method called set state which will tell this widget to rerender when this value changes.
After that, we implement the build function which defines the actual widgets that will be rebuilt every time set state is called.
I've stripped these down to the bare minimum.
We just have a text widget that will display the current value of the counter and we have a floating action button that will increment the counter when pressed.
Stateful widgets are great for managing local state, but there's a couple things I don't like here.
First of all, we have to define 2 separate classes which is sort of confusing and adds boilerplate.
And I know from experience with React JS that calling setState all over the place does not scale very well.
It's fine when we just have one property, but you can imagine how this would become a mess if we had 20 different properties on widget to update.
And with that, I'll move on to topic number 2, Stateful Builder.
There's a variety of different builder widgets in Flutter that allow you to react to different types of changes.
One of those is Stateful Builder which will allow us to simplify our stateful widget code.
Notice this time we're starting by extending a stateless widget and then we'll define our state as a counter that starts at 0.
Then the first widget that we'll add to our build method is a Stateful Builder and that takes a builder function.
That function gives us access to the build context and also a function called set state.
When we call set state, it will tell the Stateful Builder to rebuild all the widgets inside this function.
And they'll look pretty much identical to the previous example where we have text for the counter value and then a floating action button to increment it.
Now I want to point out that I'm kind of breaking the rules in Flutter.
That's why you see this green squiggly line under the class name.
This class is immutable, which means the properties on it should never be reassigned, and we're violating that by incrementing the counter.
So if you use a Stateful Builder within a Stateless Widget, I would recommend setting up your data as a map or a list because you can mutate values in those data structures without breaking the contract of the Stateless widget.
But, overall, the Stateful Builder is a nice little tool that helps you avoid the boilerplate of a Stateful widget and is really ideal when you have simple local state management to deal with.
But now things are going to start getting interesting because we're going to talk about app state or global state.
In Flutter, it's possible to pass data from top to bottom or from parent to child, but it's not really practical to pass data the other way around from child back to parent or from sibling to sibling.
But almost every non trivial app is going to have some kind of shared stayed at one point or another that runs into this limitation.
The first thing I wanna show you is inherited widget.
Now I don't recommend using this as a state management solution because there are better alternatives that already do for you, but it's important to know how it works because it's a fundamental building block in Flutter that's implemented in many other features of the framework.
Basically, it's a widget that allows you to pass context to any of its descendants no matter how far nested they are in the widget tree.
So the first thing you'll usually do is put the inherited widget towards the top of the widget tree, which we've done here with our inherited counter, and then we have our actual home page as a child of that inherited widget.
Our inherited counter will extend the inherited widget built into Flutter, then it will take a child widget as an argument to its constructor.
From there, we're going to override a method called update should notify, and this will run when this inherited widget is rebuilt and will notify any descendants whether or not they need to rebuild.
I'm just setting it to true, but you could look at the diff between the old and the new data to determine whether or not the widget actually needs to rerender.
And then it's conventional to also implement a static method called of then calls inherit from widget of exact type with the inherited counter type.
Now the inherited widget is immutable, so we could wrap it in a stateful widget to tell it when to rebuild.
But for the sake of simplicity, I'll just go ahead and define our counter data as a map.
This is a private variable.
So first we'll go ahead and define an increment method which allows us to increment the counter value, and then we'll add a getter to get the current value from the map.
Now that we have that set up, we can go down here and define our stateless widget home page.
Now just for convenience, I'm using the example we had set up previously with our stateful builder.
And inside that builder method, we can access the value from the inherited counter by calling of context with the values from that class.
Now, this may look trivial in this example, but if you imagine our home page was nested 20 levels deep, it could still access these values without having to directly pass anything through each constructor are in the widget tree.
Now like I said earlier, you probably don't need to mess with inherited widgets directly and you'll see why later in this video because there's already libraries that do similar things in a much plus awkward way.
But before we get to that point, I want to show you my personal favorite way to manage global state in a Flutter app, and that is to leverage a special type of stream in RxDart called a behavior subject.
We'll start by creating our own custom class and then give it a private value that's set to a behavior subject that starts at 0.
These are incredibly useful for state management for a variety of reasons.
First of all, they always have a current value that we can read in Flutter's build methods.
But at the same time we can treat them as a stream and a stream that we can control by adding new values to it.
And it's a broadcast stream by default, so multiple widgets can listen to the same stream.
This allows us to implement our own business logic related to the flow of data for the stream.
And we can do it completely independent of the widget tree.
That makes it much easier to test in isolation and also just easier to reason about.
Now we can define our own custom API that our widgets can consume.
For example, if we want to expose the stream, we can just call counter stream.
Then we can also create a getter that grabs the current value synchronously from the behavior subject, and and then we'll define a method to mutate the behavior subject called increment, which just adds a new value to the stream.
And that's basically all it takes to build your own custom state management solution that all of your widgets can react to and share.
Now I'm going to just instantiate it in the global namespace, which is kind of frowned upon, but I'll show you an alternative to this in just a minute.
Now that we have access to this counter service globally, we can rebuild that home page widget.
In the build method, we'll start with a scaffold, and then as the body, we'll add a stream builder.
Then we'll pass it the stream from our behavior subject.
So now every time we add a new value to the behavior subject, this widget will rebuild.
And one minor thing that you might have missed is that we're able to nest the StreamBuilder deeper in the widget tree, and that means we're repainting less of the UI than we were in previous examples.
It's not a big deal here, but it could be if you have a lot of widgets nested in the Scaffold.
The next thing we'll do is implement the builder function.
For that, we'll just return our text and that will have a snapshot of the current count or the current data from the Stream.
And the actual Cetera of that data is completely decoupled from the Stream Builder, which means we can add it outside of the build context so it doesn't need to rebuild whenever the actual value of the stream changes.
And another bonus of a StreamBuilder is that it will automatically unsubscribe from the stream when the widget is disposed.
That means you don't need to manually cancel streams to avoid memory leaks.
This is really nice and flexible, but I'd like to get this out of the global namespace and use it in a way that's more like a true singleton.
For that, I'm going to register it with a library called GetIt.
We'll go ahead and import that library and then instantiate get it.
Then we'll go into our main function and call register singleton, pass in the type counter, and then instantiate the counter.
Now we can use our counter state in any widget that requires it.
This makes the state easier to mock for integration tests and guarantees that you won't accidentally instantiate the counter class more than once.
If you're an Angular developer, I definitely think you'll like this pattern.
But now it's time to move on to the next strategy, the block pattern.
Now we could implement this entirely from Gratch, but I highly recommend using the Flutter block library.
Under the hood, it extends the inherited widget that we looked at earlier, but it provides a much more intuitive way to pass state around the widget tree.
Block is very similar to Redux if you've ever worked with React.
It provides a very explicit one way data flow that we can break down into 3 steps.
There's an event such as the user clicking on a button.
That event gets dispatched to a block, and then it will reduce the next state and emit it out as a stream so we can use it in StreamBuilder just like we did in the previous example.
The first thing we'll do is install block and Flutter block, then import them in this file.
Then we'll add the block provider to the root of the application.
The BlockProvider itself actually extends inherited widget and it takes a block type which we'll define in the next step.
All descendants of this widget will be able to access state or the data contained inside this block.
Now the next thing we need to do is define the actions or the events that the user can dispatch to the block.
We just have one single event with no data payload.
We'll define that as the counter event enum with one value of increment.
From there, we define the counter block class and it then's block which is provided by the library and we provide it with our counter event enum that we just created.
Now, the job of the block is to define the initial state.
This can be your own class, but in our case, it's just an integer that starts at 0.
The next thing we do is define a reducer function called map event to state.
It has the current state as its first argument and the event as its second argument.
If you've ever worked with Redux or NGRX, this should look very familiar.
And you'll know the next step is to define a switch statement that will look at the event itself and then determine how to reduce the next state based on that event.
So to increment a counter, we take the current state and add 1 to it.
And now we're ready to build out the actual Home page UI widget.
So this will just be a stateless widget.
And inside its build method, it can access the Counter Block which it does by calling BlockProvider of Context along with our Counter Block type.
And that should feel very natural to a Flutter developer because you do the same thing for media queries and themes and things like that.
At this point, we want to rebuild the UI when the state of the block changes.
We can do that with a Block Builder.
The Block Builder is just like a StreamBuilder, but instead of a Stream, it takes the block as an argument.
Then we can access the current state inside of this function, which in our case is just the integer of the counter.
When it comes to changing the state, we don't actually mutate the state directly like we have in previous examples.
Instead, we dispatch an action to the block.
And I really like this approach because it separates all of our business logic from the widget, which is now only concerned with rendering the UI and dispatching actions.
So it obviously took a little more code to get to this point, but the block pattern is a solid state management solution that can pay off in the long run.
Now, I don't know if you've been keeping count, but I promised you 10 different state management Solutions.
So far, we've only covered 5, but there are 5 more that you should definitely know about before making any big decisions.
The godfather of all this state management stuff is Redux, which has been the de facto state management library from the React world, but is also available in Flutter.
It follows a lot of the same concepts that we just looked at in the block pattern.
But usually, you have a single store provider for the entire app, and then you connect that store to different widgets where it's needed.
If you're brand new to state management, I would probably recommend going straight to block.
But if you're already experienced with Redux, this is definitely something you'd wanna check out.
There's another library that recently became available in Flutter that also comes from the React world, MobX.
It follows a lot of the same principles as Redux and Block, but provides some extra abstractions that I think make the process a little more developer friendly.
And one thing that's cool is that it has a CodeGen package that you can use to eliminate a lot of the boilerplate code.
That can be very useful if you want to apply these powerful state management patterns, but have a small team, or maybe you're just prototyping out some ideas quickly.
Now MobX, Redux, and Block are all state management libraries that I would consider pretty heavyweight that require a lot of explicit code.
If you just want to change some data and pass it around the widget tree, then you should check out scoped model.
This is the state management approach that they describe in the official documentation.
And like a lot of the other things we've looked at, it uses an inherited widget to pass state around the free.
But in this version, you don't have to write your own reducer functions or actions or any other boilerplate code.
Basically, you just define your data and your mutations inside of a model, then you scope that model somewhere in the widget tree.
And then you have a builder that can rebuild the UI when that model changes.
So it's a relatively simple way to deal with shared state.
The next package on this list is one I haven't actually used yet, but that looks very promising, Flutter Hooks.
I have used hooks in React JS and they definitely improve productivity and also code reusability.
This example from the docs has a useReducer hook, and you can see that hook sets up a lot of the things that we'd have to do manually like the state and the action dispatching.
So that's a really nice alternative to the Stateful Widget or some of the other approaches that we looked at for local state.
The last item on this list is one you might not expect, Firebase.
What a lot of people don't realize is that Firebase is already a state management system that is way more advanced than anything you're going to build.
It may not be a solution for every state management need, but it can handle some of the most advanced aspects of state management like user authentication, persisting data to a back end database, remote config, file uploads, and the list goes on.
The Firebase SDK exposes everything as streams or futures which is exactly what you want with a reactive framework like Flutter.
I'm gonna go ahead and wrap things up there.
If I missed anything, please let me know in the comments.
And if you want to support this channel and get access to even more content, consider becoming a Pro Member at Fireship IO.
Thanks for watching and I will talk to you soon.

Speaker 0: State management, for whatever reason, is a topic that brings out strong opinions and developers.

Speaker 1: Oh. Yeah. Um, I'm gonna have To go ahead and sort of disagree with you there.

Speaker 0: In today's video, we'll look at 10 different ways to build a basic counter app using different state management strategies in Flutter. We'll also just talk about what state management is, and why there are so many different ways to approach it. And hopefully by the end of this video, you'll know exactly which strategy is ideal for your If you're new here, like and subscribe, and you can grab a full source code on Fireship IO. And, I'm giving away another t shirt with this video. Just leave me a comment with your own opinions about state management Woah.

First of all, what is state? In a reactive framework like Flutter, you can think of your UI as the return value of a function. That function gets called with one argument, which is your state. So state is just data that changes over the life cycle of your app. A lot of your data can be self contained within a single widget.

That's known as Local State. We'll look at the tools that we have built into Flutter to manage local state, which is pretty straightforward. Things get interesting when we start talking about global state or state that needs to be shared throughout the widget tree. Coming from the web development world, I've seen tons of debate over state management and a lot of apps over engineered with these big state management libraries that didn't really need them. That's not to say they're not valuable, but even the creators and maintainers of those libraries will tell you that you probably don't need them.

We'll talk about the pros and cons of these various libraries as we go, but for now let's focus on the fundamental building blocks in Flutter, starting with the stateful widget. When you run flutter create from the command line, it gives you some starter code that increments a counter with a stateful widget. We're going to rebuild this counter multiple times throughout this video using different state management strategies. To create a StatefulWidget, we need 2 classes. The first one is the StatefulWidget itself and that implements a create state method.

And that returns our second class which is an extension of the State class. And this is where all the heavy lifting happens. 1st, we define a property called counter, which is an integer that defines the actual data state of this widget. Then we define a method called increment counter and it calls a method called set state which will tell this widget to rerender when this value changes. After that, we implement the build function which defines the actual widgets that will be rebuilt every time set state is called.

I've stripped these down to the bare minimum. We just have a text widget that will display the current value of the counter and we have a floating action button that will increment the counter when pressed. Stateful widgets are great for managing local state, but there's a couple things I don't like here. First of all, we have to define 2 separate classes which is sort of confusing and adds boilerplate. And I know from experience with React JS that calling setState all over the place does not scale very well.

It's fine when we just have one property, but you can imagine how this would become a mess if we had 20 different properties on widget to update. And with that, I'll move on to topic number 2, Stateful Builder. There's a variety of different builder widgets in Flutter that allow you to react to different types of changes. One of those is Stateful Builder which will allow us to simplify our stateful widget code. Notice this time we're starting by extending a stateless widget and then we'll define our state as a counter that starts at 0.

Then the first widget that we'll add to our build method is a Stateful Builder and that takes a builder function. That function gives us access to the build context and also a function called set state. When we call set state, it will tell the Stateful Builder to rebuild all the widgets inside this function. And they'll look pretty much identical to the previous example where we have text for the counter value and then a floating action button to increment it. Now I want to point out that I'm kind of breaking the rules in Flutter.

That's why you see this green squiggly line under the class name. This class is immutable, which means the properties on it should never be reassigned, and we're violating that by incrementing the counter. So if you use a Stateful Builder within a Stateless Widget, I would recommend setting up your data as a map or a list because you can mutate values in those data structures without breaking the contract of the Stateless widget. But, overall, the Stateful Builder is a nice little tool that helps you avoid the boilerplate of a Stateful widget and is really ideal when you have simple local state management to deal with. But now things are going to start getting interesting because we're going to talk about app state or global state.

In Flutter, it's possible to pass data from top to bottom or from parent to child, but it's not really practical to pass data the other way around from child back to parent or from sibling to sibling. But almost every non trivial app is going to have some kind of shared stayed at one point or another that runs into this limitation. The first thing I wanna show you is inherited widget. Now I don't recommend using this as a state management solution because there are better alternatives that already do for you, but it's important to know how it works because it's a fundamental building block in Flutter that's implemented in many other features of the framework. Basically, it's a widget that allows you to pass context to any of its descendants no matter how far nested they are in the widget tree.

So the first thing you'll usually do is put the inherited widget towards the top of the widget tree, which we've done here with our inherited counter, and then we have our actual home page as a child of that inherited widget. Our inherited counter will extend the inherited widget built into Flutter, then it will take a child widget as an argument to its constructor. From there, we're going to override a method called update should notify, and this will run when this inherited widget is rebuilt and will notify any descendants whether or not they need to rebuild. I'm just setting it to true, but you could look at the diff between the old and the new data to determine whether or not the widget actually needs to rerender. And then it's conventional to also implement a static method called of then calls inherit from widget of exact type with the inherited counter type.

Now the inherited widget is immutable, so we could wrap it in a stateful widget to tell it when to rebuild. But for the sake of simplicity, I'll just go ahead and define our counter data as a map. This is a private variable. So first we'll go ahead and define an increment method which allows us to increment the counter value, and then we'll add a getter to get the current value from the map. Now that we have that set up, we can go down here and define our stateless widget home page.

Now just for convenience, I'm using the example we had set up previously with our stateful builder. And inside that builder method, we can access the value from the inherited counter by calling of context with the values from that class. Now, this may look trivial in this example, but if you imagine our home page was nested 20 levels deep, it could still access these values without having to directly pass anything through each constructor are in the widget tree. Now like I said earlier, you probably don't need to mess with inherited widgets directly and you'll see why later in this video because there's already libraries that do similar things in a much plus awkward way. But before we get to that point, I want to show you my personal favorite way to manage global state in a Flutter app, and that is to leverage a special type of stream in RxDart called a behavior subject.

We'll start by creating our own custom class and then give it a private value that's set to a behavior subject that starts at 0. These are incredibly useful for state management for a variety of reasons. First of all, they always have a current value that we can read in Flutter's build methods. But at the same time we can treat them as a stream and a stream that we can control by adding new values to it. And it's a broadcast stream by default, so multiple widgets can listen to the same stream.

This allows us to implement our own business logic related to the flow of data for the stream. And we can do it completely independent of the widget tree. That makes it much easier to test in isolation and also just easier to reason about. Now we can define our own custom API that our widgets can consume. For example, if we want to expose the stream, we can just call counter stream.

Then we can also create a getter that grabs the current value synchronously from the behavior subject, and and then we'll define a method to mutate the behavior subject called increment, which just adds a new value to the stream. And that's basically all it takes to build your own custom state management solution that all of your widgets can react to and share. Now I'm going to just instantiate it in the global namespace, which is kind of frowned upon, but I'll show you an alternative to this in just a minute. Now that we have access to this counter service globally, we can rebuild that home page widget. In the build method, we'll start with a scaffold, and then as the body, we'll add a stream builder.

Then we'll pass it the stream from our behavior subject. So now every time we add a new value to the behavior subject, this widget will rebuild. And one minor thing that you might have missed is that we're able to nest the StreamBuilder deeper in the widget tree, and that means we're repainting less of the UI than we were in previous examples. It's not a big deal here, but it could be if you have a lot of widgets nested in the Scaffold. The next thing we'll do is implement the builder function.

For that, we'll just return our text and that will have a snapshot of the current count or the current data from the Stream. And the actual Cetera of that data is completely decoupled from the Stream Builder, which means we can add it outside of the build context so it doesn't need to rebuild whenever the actual value of the stream changes. And another bonus of a StreamBuilder is that it will automatically unsubscribe from the stream when the widget is disposed. That means you don't need to manually cancel streams to avoid memory leaks. This is really nice and flexible, but I'd like to get this out of the global namespace and use it in a way that's more like a true singleton.

For that, I'm going to register it with a library called GetIt. We'll go ahead and import that library and then instantiate get it. Then we'll go into our main function and call register singleton, pass in the type counter, and then instantiate the counter. Now we can use our counter state in any widget that requires it. This makes the state easier to mock for integration tests and guarantees that you won't accidentally instantiate the counter class more than once.

If you're an Angular developer, I definitely think you'll like this pattern. But now it's time to move on to the next strategy, the block pattern. Now we could implement this entirely from Gratch, but I highly recommend using the Flutter block library. Under the hood, it extends the inherited widget that we looked at earlier, but it provides a much more intuitive way to pass state around the widget tree. Block is very similar to Redux if you've ever worked with React.

It provides a very explicit one way data flow that we can break down into 3 steps. There's an event such as the user clicking on a button. That event gets dispatched to a block, and then it will reduce the next state and emit it out as a stream so we can use it in StreamBuilder just like we did in the previous example. The first thing we'll do is install block and Flutter block, then import them in this file. Then we'll add the block provider to the root of the application.

The BlockProvider itself actually extends inherited widget and it takes a block type which we'll define in the next step. All descendants of this widget will be able to access state or the data contained inside this block. Now the next thing we need to do is define the actions or the events that the user can dispatch to the block. We just have one single event with no data payload. We'll define that as the counter event enum with one value of increment.

From there, we define the counter block class and it then's block which is provided by the library and we provide it with our counter event enum that we just created. Now, the job of the block is to define the initial state. This can be your own class, but in our case, it's just an integer that starts at 0. The next thing we do is define a reducer function called map event to state. It has the current state as its first argument and the event as its second argument.

If you've ever worked with Redux or NGRX, this should look very familiar. And you'll know the next step is to define a switch statement that will look at the event itself and then determine how to reduce the next state based on that event. So to increment a counter, we take the current state and add 1 to it. And now we're ready to build out the actual Home page UI widget. So this will just be a stateless widget.

And inside its build method, it can access the Counter Block which it does by calling BlockProvider of Context along with our Counter Block type. And that should feel very natural to a Flutter developer because you do the same thing for media queries and themes and things like that. At this point, we want to rebuild the UI when the state of the block changes. We can do that with a Block Builder. The Block Builder is just like a StreamBuilder, but instead of a Stream, it takes the block as an argument.

Then we can access the current state inside of this function, which in our case is just the integer of the counter. When it comes to changing the state, we don't actually mutate the state directly like we have in previous examples. Instead, we dispatch an action to the block. And I really like this approach because it separates all of our business logic from the widget, which is now only concerned with rendering the UI and dispatching actions. So it obviously took a little more code to get to this point, but the block pattern is a solid state management solution that can pay off in the long run.

Now, I don't know if you've been keeping count, but I promised you 10 different state management Solutions. So far, we've only covered 5, but there are 5 more that you should definitely know about before making any big decisions. The godfather of all this state management stuff is Redux, which has been the de facto state management library from the React world, but is also available in Flutter. It follows a lot of the same concepts that we just looked at in the block pattern. But usually, you have a single store provider for the entire app, and then you connect that store to different widgets where it's needed.

If you're brand new to state management, I would probably recommend going straight to block. But if you're already experienced with Redux, this is definitely something you'd wanna check out. There's another library that recently became available in Flutter that also comes from the React world, MobX. It follows a lot of the same principles as Redux and Block, but provides some extra abstractions that I think make the process a little more developer friendly. And one thing that's cool is that it has a CodeGen package that you can use to eliminate a lot of the boilerplate code.

That can be very useful if you want to apply these powerful state management patterns, but have a small team, or maybe you're just prototyping out some ideas quickly. Now MobX, Redux, and Block are all state management libraries that I would consider pretty heavyweight that require a lot of explicit code. If you just want to change some data and pass it around the widget tree, then you should check out scoped model. This is the state management approach that they describe in the official documentation. And like a lot of the other things we've looked at, it uses an inherited widget to pass state around the free.

But in this version, you don't have to write your own reducer functions or actions or any other boilerplate code. Basically, you just define your data and your mutations inside of a model, then you scope that model somewhere in the widget tree. And then you have a builder that can rebuild the UI when that model changes. So it's a relatively simple way to deal with shared state. The next package on this list is one I haven't actually used yet, but that looks very promising, Flutter Hooks.

I have used hooks in React JS and they definitely improve productivity and also code reusability. This example from the docs has a useReducer hook, and you can see that hook sets up a lot of the things that we'd have to do manually like the state and the action dispatching. So that's a really nice alternative to the Stateful Widget or some of the other approaches that we looked at for local state. The last item on this list is one you might not expect, Firebase. What a lot of people don't realize is that Firebase is already a state management system that is way more advanced than anything you're going to build.

It may not be a solution for every state management need, but it can handle some of the most advanced aspects of state management like user authentication, persisting data to a back end database, remote config, file uploads, and the list goes on. The Firebase SDK exposes everything as streams or futures which is exactly what you want with a reactive framework like Flutter. I'm gonna go ahead and wrap things up there. If I missed anything, please let me know in the comments. And if you want to support this channel and get access to even more content, consider becoming a Pro Member at Fireship IO.

Thanks for watching and I will talk to you soon.
State management, for whatever reason, is a topic that brings out strong opinions and developers. Oh. Yeah. Um, I'm gonna have To go ahead and sort of disagree with you there. In today's video, we'll look at 10 different ways to build a basic counter app using different state management strategies in Flutter. We'll also just talk about what state management is, and why there are so many different ways to approach it. And hopefully by the end of this video, you'll know exactly which strategy is ideal for your If you're new here, like and subscribe, and you can grab a full source code on Fireship IO. And, I'm giving away another t shirt with this video. Just leave me a comment with your own opinions about state management Woah. First of all, what is state? In a reactive framework like Flutter, you can think of your UI as the return value of a function. That function gets called with one argument, which is your state. So state is just data that changes over the life cycle of your app. A lot of your data can be self contained within a single widget.
programming
management
policy
software
That's known as Local State. We'll look at the tools that we have built into Flutter to manage local state, which is pretty straightforward. Things get interesting when we start talking about global state or state that needs to be shared throughout the widget tree. Coming from the web development world, I've seen tons of debate over state management and a lot of apps over engineered with these big state management libraries that didn't really need them.
policy
That's not to say they're not valuable, but even the creators and maintainers of those libraries will tell you that you probably don't need them.
We'll talk about the pros and cons of these various libraries as we go, but for now let's focus on the fundamental building blocks in Flutter, starting with the stateful widget. When you run flutter create from the command line, it gives you some starter code that increments a counter with a stateful widget. We're going to rebuild this counter multiple times throughout this video using different state management strategies. To create a StatefulWidget, we need 2 classes. The first one is the StatefulWidget itself and that implements a create state method.
animation
programming
And that returns our second class which is an extension of the State class. And this is where all the heavy lifting happens. 1st, we define a property called counter, which is an integer that defines the actual data state of this widget.
Then we define a method called increment counter and it calls a method called set state which will tell this widget to rerender when this value changes. After that, we implement the build function which defines the actual widgets that will be rebuilt every time set state is called. I've stripped these down to the bare minimum.
operations
We just have a text widget that will display the current value of the counter and we have a floating action button that will increment the counter when pressed. Stateful widgets are great for managing local state, but there's a couple things I don't like here. First of all, we have to define 2 separate classes which is sort of confusing and adds boilerplate. And I know from experience with React JS that calling setState all over the place does not scale very well. It's fine when we just have one property, but you can imagine how this would become a mess if we had 20 different properties on widget to update. And with that, I'll move on to topic number 2, Stateful Builder. There's a variety of different builder widgets in Flutter that allow you to react to different types of changes. One of those is Stateful Builder which will allow us to simplify our stateful widget code. Notice this time we're starting by extending a stateless widget and then we'll define our state as a counter that starts at 0. Then the first widget that we'll add to our build method is a Stateful Builder and that takes a builder function. That function gives us access to the build context and also a function called set state.
When we call set state, it will tell the Stateful Builder to rebuild all the widgets inside this function. And they'll look pretty much identical to the previous example where we have text for the counter value and then a floating action button to increment it. Now I want to point out that I'm kind of breaking the rules in Flutter.
programming
That's why you see this green squiggly line under the class name. This class is immutable, which means the properties on it should never be reassigned, and we're violating that by incrementing the counter. So if you use a Stateful Builder within a Stateless Widget, I would recommend setting up your data as a map or a list because you can mutate values in those data structures without breaking the contract of the Stateless widget.
But, overall, the Stateful Builder is a nice little tool that helps you avoid the boilerplate of a Stateful widget and is really ideal when you have simple local state management to deal with. But now things are going to start getting interesting because we're going to talk about app state or global state.
infrastructure
In Flutter, it's possible to pass data from top to bottom or from parent to child, but it's not really practical to pass data the other way around from child back to parent or from sibling to sibling. But almost every non trivial app is going to have some kind of shared stayed at one point or another that runs into this limitation. The first thing I wanna show you is inherited widget. Now I don't recommend using this as a state management solution because there are better alternatives that already do for you, but it's important to know how it works because it's a fundamental building block in Flutter that's implemented in many other features of the framework. Basically, it's a widget that allows you to pass context to any of its descendants no matter how far nested they are in the widget tree. So the first thing you'll usually do is put the inherited widget towards the top of the widget tree, which we've done here with our inherited counter, and then we have our actual home page as a child of that inherited widget. Our inherited counter will extend the inherited widget built into Flutter, then it will take a child widget as an argument to its constructor. From there, we're going to override a method called update should notify, and this will run when this inherited widget is rebuilt and will notify any descendants whether or not they need to rebuild. I'm just setting it to true, but you could look at the diff between the old and the new data to determine whether or not the widget actually needs to rerender. And then it's conventional to also implement a static method called of then calls inherit from widget of exact type with the inherited counter type. Now the inherited widget is immutable, so we could wrap it in a stateful widget to tell it when to rebuild. But for the sake of simplicity, I'll just go ahead and define our counter data as a map. This is a private variable. So first we'll go ahead and define an increment method which allows us to increment the counter value, and then we'll add a getter to get the current value from the map.
Now that we have that set up, we can go down here and define our stateless widget home page. Now just for convenience, I'm using the example we had set up previously with our stateful builder. And inside that builder method, we can access the value from the inherited counter by calling of context with the values from that class.
home improvement
Now, this may look trivial in this example, but if you imagine our home page was nested 20 levels deep, it could still access these values without having to directly pass anything through each constructor are in the widget tree. Now like I said earlier, you probably don't need to mess with inherited widgets directly and you'll see why later in this video because there's already libraries that do similar things in a much plus awkward way.
But before we get to that point, I want to show you my personal favorite way to manage global state in a Flutter app, and that is to leverage a special type of stream in RxDart called a behavior subject. We'll start by creating our own custom class and then give it a private value that's set to a behavior subject that starts at 0.
programming
These are incredibly useful for state management for a variety of reasons. First of all, they always have a current value that we can read in Flutter's build methods. But at the same time we can treat them as a stream and a stream that we can control by adding new values to it. And it's a broadcast stream by default, so multiple widgets can listen to the same stream. This allows us to implement our own business logic related to the flow of data for the stream. And we can do it completely independent of the widget tree. That makes it much easier to test in isolation and also just easier to reason about.
streaming
telecommunications
operations
Now we can define our own custom API that our widgets can consume. For example, if we want to expose the stream, we can just call counter stream. Then we can also create a getter that grabs the current value synchronously from the behavior subject, and and then we'll define a method to mutate the behavior subject called increment, which just adds a new value to the stream. And that's basically all it takes to build your own custom state management solution that all of your widgets can react to and share. Now I'm going to just instantiate it in the global namespace, which is kind of frowned upon, but I'll show you an alternative to this in just a minute.
programming
systems
Now that we have access to this counter service globally, we can rebuild that home page widget. In the build method, we'll start with a scaffold, and then as the body, we'll add a stream builder. Then we'll pass it the stream from our behavior subject. So now every time we add a new value to the behavior subject, this widget will rebuild. And one minor thing that you might have missed is that we're able to nest the StreamBuilder deeper in the widget tree, and that means we're repainting less of the UI than we were in previous examples.
It's not a big deal here, but it could be if you have a lot of widgets nested in the Scaffold. The next thing we'll do is implement the builder function. For that, we'll just return our text and that will have a snapshot of the current count or the current data from the Stream. And the actual Cetera of that data is completely decoupled from the Stream Builder, which means we can add it outside of the build context so it doesn't need to rebuild whenever the actual value of the stream changes. And another bonus of a StreamBuilder is that it will automatically unsubscribe from the stream when the widget is disposed. That means you don't need to manually cancel streams to avoid memory leaks. This is really nice and flexible, but I'd like to get this out of the global namespace and use it in a way that's more like a true singleton.
data
streaming
visualization
For that, I'm going to register it with a library called GetIt. We'll go ahead and import that library and then instantiate get it. Then we'll go into our main function and call register singleton, pass in the type counter, and then instantiate the counter. Now we can use our counter state in any widget that requires it. This makes the state easier to mock for integration tests and guarantees that you won't accidentally instantiate the counter class more than once.
If you're an Angular developer, I definitely think you'll like this pattern. But now it's time to move on to the next strategy, the block pattern. Now we could implement this entirely from Gratch, but I highly recommend using the Flutter block library. Under the hood, it extends the inherited widget that we looked at earlier, but it provides a much more intuitive way to pass state around the widget tree.
animation
Block is very similar to Redux if you've ever worked with React. It provides a very explicit one way data flow that we can break down into 3 steps. There's an event such as the user clicking on a button. That event gets dispatched to a block, and then it will reduce the next state and emit it out as a stream so we can use it in StreamBuilder just like we did in the previous example. The first thing we'll do is install block and Flutter block, then import them in this file. Then we'll add the block provider to the root of the application. The BlockProvider itself actually extends inherited widget and it takes a block type which we'll define in the next step. All descendants of this widget will be able to access state or the data contained inside this block.
Now the next thing we need to do is define the actions or the events that the user can dispatch to the block. We just have one single event with no data payload. We'll define that as the counter event enum with one value of increment. From there, we define the counter block class and it then's block which is provided by the library and we provide it with our counter event enum that we just created.
operations
Now, the job of the block is to define the initial state. This can be your own class, but in our case, it's just an integer that starts at 0. The next thing we do is define a reducer function called map event to state. It has the current state as its first argument and the event as its second argument.
operations
If you've ever worked with Redux or NGRX, this should look very familiar. And you'll know the next step is to define a switch statement that will look at the event itself and then determine how to reduce the next state based on that event. So to increment a counter, we take the current state and add 1 to it. And now we're ready to build out the actual Home page UI widget. So this will just be a stateless widget. And inside its build method, it can access the Counter Block which it does by calling BlockProvider of Context along with our Counter Block type. And that should feel very natural to a Flutter developer because you do the same thing for media queries and themes and things like that. At this point, we want to rebuild the UI when the state of the block changes. We can do that with a Block Builder. The Block Builder is just like a StreamBuilder, but instead of a Stream, it takes the block as an argument. Then we can access the current state inside of this function, which in our case is just the integer of the counter. When it comes to changing the state, we don't actually mutate the state directly like we have in previous examples.
Instead, we dispatch an action to the block. And I really like this approach because it separates all of our business logic from the widget, which is now only concerned with rendering the UI and dispatching actions. So it obviously took a little more code to get to this point, but the block pattern is a solid state management solution that can pay off in the long run. Now, I don't know if you've been keeping count, but I promised you 10 different state management Solutions. So far, we've only covered 5, but there are 5 more that you should definitely know about before making any big decisions. The godfather of all this state management stuff is Redux, which has been the de facto state management library from the React world, but is also available in Flutter. It follows a lot of the same concepts that we just looked at in the block pattern. But usually, you have a single store provider for the entire app, and then you connect that store to different widgets where it's needed.
management
administration
policy
programming
software
operations
logic
If you're brand new to state management, I would probably recommend going straight to block. But if you're already experienced with Redux, this is definitely something you'd wanna check out. There's another library that recently became available in Flutter that also comes from the React world, MobX. It follows a lot of the same principles as Redux and Block, but provides some extra abstractions that I think make the process a little more developer friendly. And one thing that's cool is that it has a CodeGen package that you can use to eliminate a lot of the boilerplate code. That can be very useful if you want to apply these powerful state management patterns, but have a small team, or maybe you're just prototyping out some ideas quickly. Now MobX, Redux, and Block are all state management libraries that I would consider pretty heavyweight that require a lot of explicit code. If you just want to change some data and pass it around the widget tree, then you should check out scoped model. This is the state management approach that they describe in the official documentation. And like a lot of the other things we've looked at, it uses an inherited widget to pass state around the free. But in this version, you don't have to write your own reducer functions or actions or any other boilerplate code.
policy
data management
management
software
administration
software development
documentation
Basically, you just define your data and your mutations inside of a model, then you scope that model somewhere in the widget tree.
And then you have a builder that can rebuild the UI when that model changes. So it's a relatively simple way to deal with shared state. The next package on this list is one I haven't actually used yet, but that looks very promising, Flutter Hooks. I have used hooks in React JS and they definitely improve productivity and also code reusability.
programming
This example from the docs has a useReducer hook, and you can see that hook sets up a lot of the things that we'd have to do manually like the state and the action dispatching. So that's a really nice alternative to the Stateful Widget or some of the other approaches that we looked at for local state. The last item on this list is one you might not expect, Firebase. What a lot of people don't realize is that Firebase is already a state management system that is way more advanced than anything you're going to build. It may not be a solution for every state management need, but it can handle some of the most advanced aspects of state management like user authentication, persisting data to a back end database, remote config, file uploads, and the list goes on.
The Firebase SDK exposes everything as streams or futures which is exactly what you want with a reactive framework like Flutter. I'm gonna go ahead and wrap things up there. If I missed anything, please let me know in the comments. And if you want to support this channel and get access to even more content, consider becoming a Pro Member at Fireship IO.
streaming
Thanks for watching and I will talk to you soon.
State management, for whatever reason, is a topic that brings out strong opinions and developers. Oh. Yeah. Um, I'm gonna have To go ahead and sort of disagree with you there. In today's video, we'll look at 10 different ways to build a basic counter app using different state management strategies in Flutter. We'll also just talk about what state management is, and why there are so many different ways to approach it. And hopefully by the end of this video, you'll know exactly which strategy is ideal for your If you're new here, like and subscribe, and you can grab a full source code on Fireship IO. And, I'm giving away another t shirt with this video. Just leave me a comment with your own opinions about state management Woah. First of all, what is state? In a reactive framework like Flutter, you can think of your UI as the return value of a function. That function gets called with one argument, which is your state. So state is just data that changes over the life cycle of your app. A lot of your data can be self contained within a single widget. That's known as Local State. We'll look at the tools that we have built into Flutter to manage local state, which is pretty straightforward. Things get interesting when we start talking about global state or state that needs to be shared throughout the widget tree. Coming from the web development world, I've seen tons of debate over state management and a lot of apps over engineered with these big state management libraries that didn't really need them. That's not to say they're not valuable, but even the creators and maintainers of those libraries will tell you that you probably don't need them. We'll talk about the pros and cons of these various libraries as we go, but for now let's focus on the fundamental building blocks in Flutter, starting with the stateful widget. When you run flutter create from the command line, it gives you some starter code that increments a counter with a stateful widget. We're going to rebuild this counter multiple times throughout this video using different state management strategies. To create a StatefulWidget, we need 2 classes. The first one is the StatefulWidget itself and that implements a create state method. And that returns our second class which is an extension of the State class. And this is where all the heavy lifting happens. 1st, we define a property called counter, which is an integer that defines the actual data state of this widget. Then we define a method called increment counter and it calls a method called set state which will tell this widget to rerender when this value changes. After that, we implement the build function which defines the actual widgets that will be rebuilt every time set state is called. I've stripped these down to the bare minimum. We just have a text widget that will display the current value of the counter and we have a floating action button that will increment the counter when pressed. Stateful widgets are great for managing local state, but there's a couple things I don't like here. First of all, we have to define 2 separate classes which is sort of confusing and adds boilerplate. And I know from experience with React JS that calling setState all over the place does not scale very well. It's fine when we just have one property, but you can imagine how this would become a mess if we had 20 different properties on widget to update. And with that, I'll move on to topic number 2, Stateful Builder. There's a variety of different builder widgets in Flutter that allow you to react to different types of changes. One of those is Stateful Builder which will allow us to simplify our stateful widget code. Notice this time we're starting by extending a stateless widget and then we'll define our state as a counter that starts at 0. Then the first widget that we'll add to our build method is a Stateful Builder and that takes a builder function. That function gives us access to the build context and also a function called set state. When we call set state, it will tell the Stateful Builder to rebuild all the widgets inside this function. And they'll look pretty much identical to the previous example where we have text for the counter value and then a floating action button to increment it. Now I want to point out that I'm kind of breaking the rules in Flutter. That's why you see this green squiggly line under the class name. This class is immutable, which means the properties on it should never be reassigned, and we're violating that by incrementing the counter. So if you use a Stateful Builder within a Stateless Widget, I would recommend setting up your data as a map or a list because you can mutate values in those data structures without breaking the contract of the Stateless widget. But, overall, the Stateful Builder is a nice little tool that helps you avoid the boilerplate of a Stateful widget and is really ideal when you have simple local state management to deal with. But now things are going to start getting interesting because we're going to talk about app state or global state. In Flutter, it's possible to pass data from top to bottom or from parent to child, but it's not really practical to pass data the other way around from child back to parent or from sibling to sibling. But almost every non trivial app is going to have some kind of shared stayed at one point or another that runs into this limitation. The first thing I wanna show you is inherited widget. Now I don't recommend using this as a state management solution because there are better alternatives that already do for you, but it's important to know how it works because it's a fundamental building block in Flutter that's implemented in many other features of the framework. Basically, it's a widget that allows you to pass context to any of its descendants no matter how far nested they are in the widget tree. So the first thing you'll usually do is put the inherited widget towards the top of the widget tree, which we've done here with our inherited counter, and then we have our actual home page as a child of that inherited widget. Our inherited counter will extend the inherited widget built into Flutter, then it will take a child widget as an argument to its constructor. From there, we're going to override a method called update should notify, and this will run when this inherited widget is rebuilt and will notify any descendants whether or not they need to rebuild. I'm just setting it to true, but you could look at the diff between the old and the new data to determine whether or not the widget actually needs to rerender. And then it's conventional to also implement a static method called of then calls inherit from widget of exact type with the inherited counter type. Now the inherited widget is immutable, so we could wrap it in a stateful widget to tell it when to rebuild. But for the sake of simplicity, I'll just go ahead and define our counter data as a map. This is a private variable. So first we'll go ahead and define an increment method which allows us to increment the counter value, and then we'll add a getter to get the current value from the map. Now that we have that set up, we can go down here and define our stateless widget home page. Now just for convenience, I'm using the example we had set up previously with our stateful builder. And inside that builder method, we can access the value from the inherited counter by calling of context with the values from that class. Now, this may look trivial in this example, but if you imagine our home page was nested 20 levels deep, it could still access these values without having to directly pass anything through each constructor are in the widget tree. Now like I said earlier, you probably don't need to mess with inherited widgets directly and you'll see why later in this video because there's already libraries that do similar things in a much plus awkward way. But before we get to that point, I want to show you my personal favorite way to manage global state in a Flutter app, and that is to leverage a special type of stream in RxDart called a behavior subject. We'll start by creating our own custom class and then give it a private value that's set to a behavior subject that starts at 0. These are incredibly useful for state management for a variety of reasons. First of all, they always have a current value that we can read in Flutter's build methods. But at the same time we can treat them as a stream and a stream that we can control by adding new values to it. And it's a broadcast stream by default, so multiple widgets can listen to the same stream. This allows us to implement our own business logic related to the flow of data for the stream. And we can do it completely independent of the widget tree. That makes it much easier to test in isolation and also just easier to reason about. Now we can define our own custom API that our widgets can consume. For example, if we want to expose the stream, we can just call counter stream. Then we can also create a getter that grabs the current value synchronously from the behavior subject, and and then we'll define a method to mutate the behavior subject called increment, which just adds a new value to the stream. And that's basically all it takes to build your own custom state management solution that all of your widgets can react to and share. Now I'm going to just instantiate it in the global namespace, which is kind of frowned upon, but I'll show you an alternative to this in just a minute. Now that we have access to this counter service globally, we can rebuild that home page widget. In the build method, we'll start with a scaffold, and then as the body, we'll add a stream builder. Then we'll pass it the stream from our behavior subject. So now every time we add a new value to the behavior subject, this widget will rebuild. And one minor thing that you might have missed is that we're able to nest the StreamBuilder deeper in the widget tree, and that means we're repainting less of the UI than we were in previous examples. It's not a big deal here, but it could be if you have a lot of widgets nested in the Scaffold. The next thing we'll do is implement the builder function. For that, we'll just return our text and that will have a snapshot of the current count or the current data from the Stream. And the actual Cetera of that data is completely decoupled from the Stream Builder, which means we can add it outside of the build context so it doesn't need to rebuild whenever the actual value of the stream changes. And another bonus of a StreamBuilder is that it will automatically unsubscribe from the stream when the widget is disposed. That means you don't need to manually cancel streams to avoid memory leaks. This is really nice and flexible, but I'd like to get this out of the global namespace and use it in a way that's more like a true singleton. For that, I'm going to register it with a library called GetIt. We'll go ahead and import that library and then instantiate get it. Then we'll go into our main function and call register singleton, pass in the type counter, and then instantiate the counter. Now we can use our counter state in any widget that requires it. This makes the state easier to mock for integration tests and guarantees that you won't accidentally instantiate the counter class more than once. If you're an Angular developer, I definitely think you'll like this pattern. But now it's time to move on to the next strategy, the block pattern. Now we could implement this entirely from Gratch, but I highly recommend using the Flutter block library. Under the hood, it extends the inherited widget that we looked at earlier, but it provides a much more intuitive way to pass state around the widget tree. Block is very similar to Redux if you've ever worked with React. It provides a very explicit one way data flow that we can break down into 3 steps. There's an event such as the user clicking on a button. That event gets dispatched to a block, and then it will reduce the next state and emit it out as a stream so we can use it in StreamBuilder just like we did in the previous example. The first thing we'll do is install block and Flutter block, then import them in this file. Then we'll add the block provider to the root of the application. The BlockProvider itself actually extends inherited widget and it takes a block type which we'll define in the next step. All descendants of this widget will be able to access state or the data contained inside this block. Now the next thing we need to do is define the actions or the events that the user can dispatch to the block. We just have one single event with no data payload. We'll define that as the counter event enum with one value of increment. From there, we define the counter block class and it then's block which is provided by the library and we provide it with our counter event enum that we just created. Now, the job of the block is to define the initial state. This can be your own class, but in our case, it's just an integer that starts at 0. The next thing we do is define a reducer function called map event to state. It has the current state as its first argument and the event as its second argument. If you've ever worked with Redux or NGRX, this should look very familiar. And you'll know the next step is to define a switch statement that will look at the event itself and then determine how to reduce the next state based on that event. So to increment a counter, we take the current state and add 1 to it. And now we're ready to build out the actual Home page UI widget. So this will just be a stateless widget. And inside its build method, it can access the Counter Block which it does by calling BlockProvider of Context along with our Counter Block type. And that should feel very natural to a Flutter developer because you do the same thing for media queries and themes and things like that. At this point, we want to rebuild the UI when the state of the block changes. We can do that with a Block Builder. The Block Builder is just like a StreamBuilder, but instead of a Stream, it takes the block as an argument. Then we can access the current state inside of this function, which in our case is just the integer of the counter. When it comes to changing the state, we don't actually mutate the state directly like we have in previous examples. Instead, we dispatch an action to the block. And I really like this approach because it separates all of our business logic from the widget, which is now only concerned with rendering the UI and dispatching actions. So it obviously took a little more code to get to this point, but the block pattern is a solid state management solution that can pay off in the long run. Now, I don't know if you've been keeping count, but I promised you 10 different state management Solutions. So far, we've only covered 5, but there are 5 more that you should definitely know about before making any big decisions. The godfather of all this state management stuff is Redux, which has been the de facto state management library from the React world, but is also available in Flutter. It follows a lot of the same concepts that we just looked at in the block pattern. But usually, you have a single store provider for the entire app, and then you connect that store to different widgets where it's needed. If you're brand new to state management, I would probably recommend going straight to block. But if you're already experienced with Redux, this is definitely something you'd wanna check out. There's another library that recently became available in Flutter that also comes from the React world, MobX. It follows a lot of the same principles as Redux and Block, but provides some extra abstractions that I think make the process a little more developer friendly. And one thing that's cool is that it has a CodeGen package that you can use to eliminate a lot of the boilerplate code. That can be very useful if you want to apply these powerful state management patterns, but have a small team, or maybe you're just prototyping out some ideas quickly. Now MobX, Redux, and Block are all state management libraries that I would consider pretty heavyweight that require a lot of explicit code. If you just want to change some data and pass it around the widget tree, then you should check out scoped model. This is the state management approach that they describe in the official documentation. And like a lot of the other things we've looked at, it uses an inherited widget to pass state around the free. But in this version, you don't have to write your own reducer functions or actions or any other boilerplate code. Basically, you just define your data and your mutations inside of a model, then you scope that model somewhere in the widget tree. And then you have a builder that can rebuild the UI when that model changes. So it's a relatively simple way to deal with shared state. The next package on this list is one I haven't actually used yet, but that looks very promising, Flutter Hooks. I have used hooks in React JS and they definitely improve productivity and also code reusability. This example from the docs has a useReducer hook, and you can see that hook sets up a lot of the things that we'd have to do manually like the state and the action dispatching. So that's a really nice alternative to the Stateful Widget or some of the other approaches that we looked at for local state. The last item on this list is one you might not expect, Firebase. What a lot of people don't realize is that Firebase is already a state management system that is way more advanced than anything you're going to build. It may not be a solution for every state management need, but it can handle some of the most advanced aspects of state management like user authentication, persisting data to a back end database, remote config, file uploads, and the list goes on. The Firebase SDK exposes everything as streams or futures which is exactly what you want with a reactive framework like Flutter. I'm gonna go ahead and wrap things up there. If I missed anything, please let me know in the comments. And if you want to support this channel and get access to even more content, consider becoming a Pro Member at Fireship IO. Thanks for watching and I will talk to you soon.
State
state
management,
management
for
for
whatever
whatever
reason,
reason
is
is
a
a
topic
topic
that
that
brings
brings
out
out
strong
strong
opinions
opinions
and
and
developers.
developers
Oh.
oh
Yeah.
yeah
Um,
um
I'm
i'm
gonna
gonna
have
have
To
to
go
go
ahead
ahead
and
and
sort
sort
of
of
disagree
disagree
with
with
you
you
there.
there
In
in
today's
today's
video,
video
we'll
we'll
look
look
at
at
10
10
different
different
ways
ways
to
to
build
build
a
a
basic
basic
counter
counter
app
app
using
using
different
different
state
state
management
management
strategies
strategies
in
in
Flutter.
flutter
We'll
we'll
also
also
just
just
talk
talk
about
about
what
what
state
state
management
management
is,
is
and
and
why
why
there
there
are
are
so
so
many
many
different
different
ways
ways
to
to
approach
approach
it.
it
And
and
hopefully
hopefully
by
by
the
the
end
end
of
of
this
this
video,
video
you'll
you'll
know
know
exactly
exactly
which
which
strategy
strategy
is
is
ideal
ideal
for
for
your
your
If
if
you're
you're
new
new
here,
here
like
like
and
and
subscribe,
subscribe
and
and
you
you
can
can
grab
grab
a
a
full
full
source
source
code
code
on
on
Fireship
fireship
IO.
io
And,
and
I'm
i'm
giving
giving
away
away
another
another
t
t
shirt
shirt
with
with
this
this
video.
video
Just
just
leave
leave
me
me
a
a
comment
comment
with
with
your
your
own
own
opinions
opinions
about
about
state
state
management
management
Woah.
woah
First
first
of
of
all,
all
what
what
is
is
state?
state
In
in
a
a
reactive
reactive
framework
framework
like
like
Flutter,
flutter
you
you
can
can
think
think
of
of
your
your
UI
ui
as
as
the
the
return
return
value
value
of
of
a
a
function.
function
That
that
function
function
gets
gets
called
called
with
with
one
one
argument,
argument
which
which
is
is
your
your
state.
state
So
so
state
state
is
is
just
just
data
data
that
that
changes
changes
over
over
the
the
life
life
cycle
cycle
of
of
your
your
app.
app
A
a
lot
lot
of
of
your
your
data
data
can
can
be
be
self
self
contained
contained
within
within
a
a
single
single
widget.
widget
That's
that's
known
known
as
as
Local
local
State.
state
We'll
we'll
look
look
at
at
the
the
tools
tools
that
that
we
we
have
have
built
built
into
into
Flutter
flutter
to
to
manage
manage
local
local
state,
state
which
which
is
is
pretty
pretty
straightforward.
straightforward
Things
things
get
get
interesting
interesting
when
when
we
we
start
start
talking
talking
about
about
global
global
state
state
or
or
state
state
that
that
needs
needs
to
to
be
be
shared
shared
throughout
throughout
the
the
widget
widget
tree.
tree
Coming
coming
from
from
the
the
web
web
development
development
world,
world
I've
i've
seen
seen
tons
tons
of
of
debate
debate
over
over
state
state
management
management
and
and
a
a
lot
lot
of
of
apps
apps
over
over
engineered
engineered
with
with
these
these
big
big
state
state
management
management
libraries
libraries
that
that
didn't
didn't
really
really
need
need
them.
them
That's
that's
not
not
to
to
say
say
they're
they're
not
not
valuable,
valuable
but
but
even
even
the
the
creators
creators
and
and
maintainers
maintainers
of
of
those
those
libraries
libraries
will
will
tell
tell
you
you
that
that
you
you
probably
probably
don't
don't
need
need
them.
them
We'll
we'll
talk
talk
about
about
the
the
pros
pros
and
and
cons
cons
of
of
these
these
various
various
libraries
libraries
as
as
we
we
go,
go
but
but
for
for
now
now
let's
let's
focus
focus
on
on
the
the
fundamental
fundamental
building
building
blocks
blocks
in
in
Flutter,
flutter
starting
starting
with
with
the
the
stateful
stateful
widget.
widget
When
when
you
you
run
run
flutter
flutter
create
create
from
from
the
the
command
command
line,
line
it
it
gives
gives
you
you
some
some
starter
starter
code
code
that
that
increments
increments
a
a
counter
counter
with
with
a
a
stateful
stateful
widget.
widget
We're
we're
going
going
to
to
rebuild
rebuild
this
this
counter
counter
multiple
multiple
times
times
throughout
throughout
this
this
video
video
using
using
different
different
state
state
management
management
strategies.
strategies
To
to
create
create
a
a
StatefulWidget,
statefulwidget
we
we
need
need
2
2
classes.
classes
The
the
first
first
one
one
is
is
the
the
StatefulWidget
statefulwidget
itself
itself
and
and
that
that
implements
implements
a
a
create
create
state
state
method.
method
And
and
that
that
returns
returns
our
our
second
second
class
class
which
which
is
is
an
an
extension
extension
of
of
the
the
State
state
class.
class
And
and
this
this
is
is
where
where
all
all
the
the
heavy
heavy
lifting
lifting
happens.
happens
1st,
1st
we
we
define
define
a
a
property
property
called
called
counter,
counter
which
which
is
is
an
an
integer
integer
that
that
defines
defines
the
the
actual
actual
data
data
state
state
of
of
this
this
widget.
widget
Then
then
we
we
define
define
a
a
method
method
called
called
increment
increment
counter
counter
and
and
it
it
calls
calls
a
a
method
method
called
called
set
set
state
state
which
which
will
will
tell
tell
this
this
widget
widget
to
to
rerender
rerender
when
when
this
this
value
value
changes.
changes
After
after
that,
that
we
we
implement
implement
the
the
build
build
function
function
which
which
defines
defines
the
the
actual
actual
widgets
widgets
that
that
will
will
be
be
rebuilt
rebuilt
every
every
time
time
set
set
state
state
is
is
called.
called
I've
i've
stripped
stripped
these
these
down
down
to
to
the
the
bare
bare
minimum.
minimum
We
we
just
just
have
have
a
a
text
text
widget
widget
that
that
will
will
display
display
the
the
current
current
value
value
of
of
the
the
counter
counter
and
and
we
we
have
have
a
a
floating
floating
action
action
button
button
that
that
will
will
increment
increment
the
the
counter
counter
when
when
pressed.
pressed
Stateful
stateful
widgets
widgets
are
are
great
great
for
for
managing
managing
local
local
state,
state
but
but
there's
there's
a
a
couple
couple
things
things
I
i
don't
don't
like
like
here.
here
First
first
of
of
all,
all
we
we
have
have
to
to
define
define
2
2
separate
separate
classes
classes
which
which
is
is
sort
sort
of
of
confusing
confusing
and
and
adds
adds
boilerplate.
boilerplate
And
and
I
i
know
know
from
from
experience
experience
with
with
React
react
JS
js
that
that
calling
calling
setState
setstate
all
all
over
over
the
the
place
place
does
does
not
not
scale
scale
very
very
well.
well
It's
it's
fine
fine
when
when
we
we
just
just
have
have
one
one
property,
property
but
but
you
you
can
can
imagine
imagine
how
how
this
this
would
would
become
become
a
a
mess
mess
if
if
we
we
had
had
20
20
different
different
properties
properties
on
on
widget
widget
to
to
update.
update
And
and
with
with
that,
that
I'll
i'll
move
move
on
on
to
to
topic
topic
number
number
2,
2
Stateful
stateful
Builder.
builder
There's
there's
a
a
variety
variety
of
of
different
different
builder
builder
widgets
widgets
in
in
Flutter
flutter
that
that
allow
allow
you
you
to
to
react
react
to
to
different
different
types
types
of
of
changes.
changes
One
one
of
of
those
those
is
is
Stateful
stateful
Builder
builder
which
which
will
will
allow
allow
us
us
to
to
simplify
simplify
our
our
stateful
stateful
widget
widget
code.
code
Notice
notice
this
this
time
time
we're
we're
starting
starting
by
by
extending
extending
a
a
stateless
stateless
widget
widget
and
and
then
then
we'll
we'll
define
define
our
our
state
state
as
as
a
a
counter
counter
that
that
starts
starts
at
at
0.
0
Then
then
the
the
first
first
widget
widget
that
that
we'll
we'll
add
add
to
to
our
our
build
build
method
method
is
is
a
a
Stateful
stateful
Builder
builder
and
and
that
that
takes
takes
a
a
builder
builder
function.
function
That
that
function
function
gives
gives
us
us
access
access
to
to
the
the
build
build
context
context
and
and
also
also
a
a
function
function
called
called
set
set
state.
state
When
when
we
we
call
call
set
set
state,
state
it
it
will
will
tell
tell
the
the
Stateful
stateful
Builder
builder
to
to
rebuild
rebuild
all
all
the
the
widgets
widgets
inside
inside
this
this
function.
function
And
and
they'll
they'll
look
look
pretty
pretty
much
much
identical
identical
to
to
the
the
previous
previous
example
example
where
where
we
we
have
have
text
text
for
for
the
the
counter
counter
value
value
and
and
then
then
a
a
floating
floating
action
action
button
button
to
to
increment
increment
it.
it
Now
now
I
i
want
want
to
to
point
point
out
out
that
that
I'm
i'm
kind
kind
of
of
breaking
breaking
the
the
rules
rules
in
in
Flutter.
flutter
That's
that's
why
why
you
you
see
see
this
this
green
green
squiggly
squiggly
line
line
under
under
the
the
class
class
name.
name
This
this
class
class
is
is
immutable,
immutable
which
which
means
means
the
the
properties
properties
on
on
it
it
should
should
never
never
be
be
reassigned,
reassigned
and
and
we're
we're
violating
violating
that
that
by
by
incrementing
incrementing
the
the
counter.
counter
So
so
if
if
you
you
use
use
a
a
Stateful
stateful
Builder
builder
within
within
a
a
Stateless
stateless
Widget,
widget
I
i
would
would
recommend
recommend
setting
setting
up
up
your
your
data
data
as
as
a
a
map
map
or
or
a
a
list
list
because
because
you
you
can
can
mutate
mutate
values
values
in
in
those
those
data
data
structures
structures
without
without
breaking
breaking
the
the
contract
contract
of
of
the
the
Stateless
stateless
widget.
widget
But,
but
overall,
overall
the
the
Stateful
stateful
Builder
builder
is
is
a
a
nice
nice
little
little
tool
tool
that
that
helps
helps
you
you
avoid
avoid
the
the
boilerplate
boilerplate
of
of
a
a
Stateful
stateful
widget
widget
and
and
is
is
really
really
ideal
ideal
when
when
you
you
have
have
simple
simple
local
local
state
state
management
management
to
to
deal
deal
with.
with
But
but
now
now
things
things
are
are
going
going
to
to
start
start
getting
getting
interesting
interesting
because
because
we're
we're
going
going
to
to
talk
talk
about
about
app
app
state
state
or
or
global
global
state.
state
In
in
Flutter,
flutter
it's
it's
possible
possible
to
to
pass
pass
data
data
from
from
top
top
to
to
bottom
bottom
or
or
from
from
parent
parent
to
to
child,
child
but
but
it's
it's
not
not
really
really
practical
practical
to
to
pass
pass
data
data
the
the
other
other
way
way
around
around
from
from
child
child
back
back
to
to
parent
parent
or
or
from
from
sibling
sibling
to
to
sibling.
sibling
But
but
almost
almost
every
every
non
non
trivial
trivial
app
app
is
is
going
going
to
to
have
have
some
some
kind
kind
of
of
shared
shared
stayed
stayed
at
at
one
one
point
point
or
or
another
another
that
that
runs
runs
into
into
this
this
limitation.
limitation
The
the
first
first
thing
thing
I
i
wanna
wanna
show
show
you
you
is
is
inherited
inherited
widget.
widget
Now
now
I
i
don't
don't
recommend
recommend
using
using
this
this
as
as
a
a
state
state
management
management
solution
solution
because
because
there
there
are
are
better
better
alternatives
alternatives
that
that
already
already
do
do
for
for
you,
you
but
but
it's
it's
important
important
to
to
know
know
how
how
it
it
works
works
because
because
it's
it's
a
a
fundamental
fundamental
building
building
block
block
in
in
Flutter
flutter
that's
that's
implemented
implemented
in
in
many
many
other
other
features
features
of
of
the
the
framework.
framework
Basically,
basically
it's
it's
a
a
widget
widget
that
that
allows
allows
you
you
to
to
pass
pass
context
context
to
to
any
any
of
of
its
its
descendants
descendants
no
no
matter
matter
how
how
far
far
nested
nested
they
they
are
are
in
in
the
the
widget
widget
tree.
tree
So
so
the
the
first
first
thing
thing
you'll
you'll
usually
usually
do
do
is
is
put
put
the
the
inherited
inherited
widget
widget
towards
towards
the
the
top
top
of
of
the
the
widget
widget
tree,
tree
which
which
we've
we've
done
done
here
here
with
with
our
our
inherited
inherited
counter,
counter
and
and
then
then
we
we
have
have
our
our
actual
actual
home
home
page
page
as
as
a
a
child
child
of
of
that
that
inherited
inherited
widget.
widget
Our
our
inherited
inherited
counter
counter
will
will
extend
extend
the
the
inherited
inherited
widget
widget
built
built
into
into
Flutter,
flutter
then
then
it
it
will
will
take
take
a
a
child
child
widget
widget
as
as
an
an
argument
argument
to
to
its
its
constructor.
constructor
From
from
there,
there
we're
we're
going
going
to
to
override
override
a
a
method
method
called
called
update
update
should
should
notify,
notify
and
and
this
this
will
will
run
run
when
when
this
this
inherited
inherited
widget
widget
is
is
rebuilt
rebuilt
and
and
will
will
notify
notify
any
any
descendants
descendants
whether
whether
or
or
not
not
they
they
need
need
to
to
rebuild.
rebuild
I'm
i'm
just
just
setting
setting
it
it
to
to
true,
true
but
but
you
you
could
could
look
look
at
at
the
the
diff
diff
between
between
the
the
old
old
and
and
the
the
new
new
data
data
to
to
determine
determine
whether
whether
or
or
not
not
the
the
widget
widget
actually
actually
needs
needs
to
to
rerender.
rerender
And
and
then
then
it's
it's
conventional
conventional
to
to
also
also
implement
implement
a
a
static
static
method
method
called
called
of
of
then
then
calls
calls
inherit
inherit
from
from
widget
widget
of
of
exact
exact
type
type
with
with
the
the
inherited
inherited
counter
counter
type.
type
Now
now
the
the
inherited
inherited
widget
widget
is
is
immutable,
immutable
so
so
we
we
could
could
wrap
wrap
it
it
in
in
a
a
stateful
stateful
widget
widget
to
to
tell
tell
it
it
when
when
to
to
rebuild.
rebuild
But
but
for
for
the
the
sake
sake
of
of
simplicity,
simplicity
I'll
i'll
just
just
go
go
ahead
ahead
and
and
define
define
our
our
counter
counter
data
data
as
as
a
a
map.
map
This
this
is
is
a
a
private
private
variable.
variable
So
so
first
first
we'll
we'll
go
go
ahead
ahead
and
and
define
define
an
an
increment
increment
method
method
which
which
allows
allows
us
us
to
to
increment
increment
the
the
counter
counter
value,
value
and
and
then
then
we'll
we'll
add
add
a
a
getter
getter
to
to
get
get
the
the
current
current
value
value
from
from
the
the
map.
map
Now
now
that
that
we
we
have
have
that
that
set
set
up,
up
we
we
can
can
go
go
down
down
here
here
and
and
define
define
our
our
stateless
stateless
widget
widget
home
home
page.
page
Now
now
just
just
for
for
convenience,
convenience
I'm
i'm
using
using
the
the
example
example
we
we
had
had
set
set
up
up
previously
previously
with
with
our
our
stateful
stateful
builder.
builder
And
and
inside
inside
that
that
builder
builder
method,
method
we
we
can
can
access
access
the
the
value
value
from
from
the
the
inherited
inherited
counter
counter
by
by
calling
calling
of
of
context
context
with
with
the
the
values
values
from
from
that
that
class.
class
Now,
now
this
this
may
may
look
look
trivial
trivial
in
in
this
this
example,
example
but
but
if
if
you
you
imagine
imagine
our
our
home
home
page
page
was
was
nested
nested
20
20
levels
levels
deep,
deep
it
it
could
could
still
still
access
access
these
these
values
values
without
without
having
having
to
to
directly
directly
pass
pass
anything
anything
through
through
each
each
constructor
constructor
are
are
in
in
the
the
widget
widget
tree.
tree
Now
now
like
like
I
i
said
said
earlier,
earlier
you
you
probably
probably
don't
don't
need
need
to
to
mess
mess
with
with
inherited
inherited
widgets
widgets
directly
directly
and
and
you'll
you'll
see
see
why
why
later
later
in
in
this
this
video
video
because
because
there's
there's
already
already
libraries
libraries
that
that
do
do
similar
similar
things
things
in
in
a
a
much
much
plus
plus
awkward
awkward
way.
way
But
but
before
before
we
we
get
get
to
to
that
that
point,
point
I
i
want
want
to
to
show
show
you
you
my
my
personal
personal
favorite
favorite
way
way
to
to
manage
manage
global
global
state
state
in
in
a
a
Flutter
flutter
app,
app
and
and
that
that
is
is
to
to
leverage
leverage
a
a
special
special
type
type
of
of
stream
stream
in
in
RxDart
rxdart
called
called
a
a
behavior
behavior
subject.
subject
We'll
we'll
start
start
by
by
creating
creating
our
our
own
own
custom
custom
class
class
and
and
then
then
give
give
it
it
a
a
private
private
value
value
that's
that's
set
set
to
to
a
a
behavior
behavior
subject
subject
that
that
starts
starts
at
at
0.
0
These
these
are
are
incredibly
incredibly
useful
useful
for
for
state
state
management
management
for
for
a
a
variety
variety
of
of
reasons.
reasons
First
first
of
of
all,
all
they
they
always
always
have
have
a
a
current
current
value
value
that
that
we
we
can
can
read
read
in
in
Flutter's
flutter's
build
build
methods.
methods
But
but
at
at
the
the
same
same
time
time
we
we
can
can
treat
treat
them
them
as
as
a
a
stream
stream
and
and
a
a
stream
stream
that
that
we
we
can
can
control
control
by
by
adding
adding
new
new
values
values
to
to
it.
it
And
and
it's
it's
a
a
broadcast
broadcast
stream
stream
by
by
default,
default
so
so
multiple
multiple
widgets
widgets
can
can
listen
listen
to
to
the
the
same
same
stream.
stream
This
this
allows
allows
us
us
to
to
implement
implement
our
our
own
own
business
business
logic
logic
related
related
to
to
the
the
flow
flow
of
of
data
data
for
for
the
the
stream.
stream
And
and
we
we
can
can
do
do
it
it
completely
completely
independent
independent
of
of
the
the
widget
widget
tree.
tree
That
that
makes
makes
it
it
much
much
easier
easier
to
to
test
test
in
in
isolation
isolation
and
and
also
also
just
just
easier
easier
to
to
reason
reason
about.
about
Now
now
we
we
can
can
define
define
our
our
own
own
custom
custom
API
api
that
that
our
our
widgets
widgets
can
can
consume.
consume
For
for
example,
example
if
if
we
we
want
want
to
to
expose
expose
the
the
stream,
stream
we
we
can
can
just
just
call
call
counter
counter
stream.
stream
Then
then
we
we
can
can
also
also
create
create
a
a
getter
getter
that
that
grabs
grabs
the
the
current
current
value
value
synchronously
synchronously
from
from
the
the
behavior
behavior
subject,
subject
and
and
and
and
then
then
we'll
we'll
define
define
a
a
method
method
to
to
mutate
mutate
the
the
behavior
behavior
subject
subject
called
called
increment,
increment
which
which
just
just
adds
adds
a
a
new
new
value
value
to
to
the
the
stream.
stream
And
and
that's
that's
basically
basically
all
all
it
it
takes
takes
to
to
build
build
your
your
own
own
custom
custom
state
state
management
management
solution
solution
that
that
all
all
of
of
your
your
widgets
widgets
can
can
react
react
to
to
and
and
share.
share
Now
now
I'm
i'm
going
going
to
to
just
just
instantiate
instantiate
it
it
in
in
the
the
global
global
namespace,
namespace
which
which
is
is
kind
kind
of
of
frowned
frowned
upon,
upon
but
but
I'll
i'll
show
show
you
you
an
an
alternative
alternative
to
to
this
this
in
in
just
just
a
a
minute.
minute
Now
now
that
that
we
we
have
have
access
access
to
to
this
this
counter
counter
service
service
globally,
globally
we
we
can
can
rebuild
rebuild
that
that
home
home
page
page
widget.
widget
In
in
the
the
build
build
method,
method
we'll
we'll
start
start
with
with
a
a
scaffold,
scaffold
and
and
then
then
as
as
the
the
body,
body
we'll
we'll
add
add
a
a
stream
stream
builder.
builder
Then
then
we'll
we'll
pass
pass
it
it
the
the
stream
stream
from
from
our
our
behavior
behavior
subject.
subject
So
so
now
now
every
every
time
time
we
we
add
add
a
a
new
new
value
value
to
to
the
the
behavior
behavior
subject,
subject
this
this
widget
widget
will
will
rebuild.
rebuild
And
and
one
one
minor
minor
thing
thing
that
that
you
you
might
might
have
have
missed
missed
is
is
that
that
we're
we're
able
able
to
to
nest
nest
the
the
StreamBuilder
streambuilder
deeper
deeper
in
in
the
the
widget
widget
tree,
tree
and
and
that
that
means
means
we're
we're
repainting
repainting
less
less
of
of
the
the
UI
ui
than
than
we
we
were
were
in
in
previous
previous
examples.
examples
It's
it's
not
not
a
a
big
big
deal
deal
here,
here
but
but
it
it
could
could
be
be
if
if
you
you
have
have
a
a
lot
lot
of
of
widgets
widgets
nested
nested
in
in
the
the
Scaffold.
scaffold
The
the
next
next
thing
thing
we'll
we'll
do
do
is
is
implement
implement
the
the
builder
builder
function.
function
For
for
that,
that
we'll
we'll
just
just
return
return
our
our
text
text
and
and
that
that
will
will
have
have
a
a
snapshot
snapshot
of
of
the
the
current
current
count
count
or
or
the
the
current
current
data
data
from
from
the
the
Stream.
stream
And
and
the
the
actual
actual
Cetera
cetera
of
of
that
that
data
data
is
is
completely
completely
decoupled
decoupled
from
from
the
the
Stream
stream
Builder,
builder
which
which
means
means
we
we
can
can
add
add
it
it
outside
outside
of
of
the
the
build
build
context
context
so
so
it
it
doesn't
doesn't
need
need
to
to
rebuild
rebuild
whenever
whenever
the
the
actual
actual
value
value
of
of
the
the
stream
stream
changes.
changes
And
and
another
another
bonus
bonus
of
of
a
a
StreamBuilder
streambuilder
is
is
that
that
it
it
will
will
automatically
automatically
unsubscribe
unsubscribe
from
from
the
the
stream
stream
when
when
the
the
widget
widget
is
is
disposed.
disposed
That
that
means
means
you
you
don't
don't
need
need
to
to
manually
manually
cancel
cancel
streams
streams
to
to
avoid
avoid
memory
memory
leaks.
leaks
This
this
is
is
really
really
nice
nice
and
and
flexible,
flexible
but
but
I'd
i'd
like
like
to
to
get
get
this
this
out
out
of
of
the
the
global
global
namespace
namespace
and
and
use
use
it
it
in
in
a
a
way
way
that's
that's
more
more
like
like
a
a
true
true
singleton.
singleton
For
for
that,
that
I'm
i'm
going
going
to
to
register
register
it
it
with
with
a
a
library
library
called
called
GetIt.
getit
We'll
we'll
go
go
ahead
ahead
and
and
import
import
that
that
library
library
and
and
then
then
instantiate
instantiate
get
get
it.
it
Then
then
we'll
we'll
go
go
into
into
our
our
main
main
function
function
and
and
call
call
register
register
singleton,
singleton
pass
pass
in
in
the
the
type
type
counter,
counter
and
and
then
then
instantiate
instantiate
the
the
counter.
counter
Now
now
we
we
can
can
use
use
our
our
counter
counter
state
state
in
in
any
any
widget
widget
that
that
requires
requires
it.
it
This
this
makes
makes
the
the
state
state
easier
easier
to
to
mock
mock
for
for
integration
integration
tests
tests
and
and
guarantees
guarantees
that
that
you
you
won't
won't
accidentally
accidentally
instantiate
instantiate
the
the
counter
counter
class
class
more
more
than
than
once.
once
If
if
you're
you're
an
an
Angular
angular
developer,
developer
I
i
definitely
definitely
think
think
you'll
you'll
like
like
this
this
pattern.
pattern
But
but
now
now
it's
it's
time
time
to
to
move
move
on
on
to
to
the
the
next
next
strategy,
strategy
the
the
block
block
pattern.
pattern
Now
now
we
we
could
could
implement
implement
this
this
entirely
entirely
from
from
Gratch,
gratch
but
but
I
i
highly
highly
recommend
recommend
using
using
the
the
Flutter
flutter
block
block
library.
library
Under
under
the
the
hood,
hood
it
it
extends
extends
the
the
inherited
inherited
widget
widget
that
that
we
we
looked
looked
at
at
earlier,
earlier
but
but
it
it
provides
provides
a
a
much
much
more
more
intuitive
intuitive
way
way
to
to
pass
pass
state
state
around
around
the
the
widget
widget
tree.
tree
Block
block
is
is
very
very
similar
similar
to
to
Redux
redux
if
if
you've
you've
ever
ever
worked
worked
with
with
React.
react
It
it
provides
provides
a
a
very
very
explicit
explicit
one
one
way
way
data
data
flow
flow
that
that
we
we
can
can
break
break
down
down
into
into
3
3
steps.
steps
There's
there's
an
an
event
event
such
such
as
as
the
the
user
user
clicking
clicking
on
on
a
a
button.
button
That
that
event
event
gets
gets
dispatched
dispatched
to
to
a
a
block,
block
and
and
then
then
it
it
will
will
reduce
reduce
the
the
next
next
state
state
and
and
emit
emit
it
it
out
out
as
as
a
a
stream
stream
so
so
we
we
can
can
use
use
it
it
in
in
StreamBuilder
streambuilder
just
just
like
like
we
we
did
did
in
in
the
the
previous
previous
example.
example
The
the
first
first
thing
thing
we'll
we'll
do
do
is
is
install
install
block
block
and
and
Flutter
flutter
block,
block
then
then
import
import
them
them
in
in
this
this
file.
file
Then
then
we'll
we'll
add
add
the
the
block
block
provider
provider
to
to
the
the
root
root
of
of
the
the
application.
application
The
the
BlockProvider
blockprovider
itself
itself
actually
actually
extends
extends
inherited
inherited
widget
widget
and
and
it
it
takes
takes
a
a
block
block
type
type
which
which
we'll
we'll
define
define
in
in
the
the
next
next
step.
step
All
all
descendants
descendants
of
of
this
this
widget
widget
will
will
be
be
able
able
to
to
access
access
state
state
or
or
the
the
data
data
contained
contained
inside
inside
this
this
block.
block
Now
now
the
the
next
next
thing
thing
we
we
need
need
to
to
do
do
is
is
define
define
the
the
actions
actions
or
or
the
the
events
events
that
that
the
the
user
user
can
can
dispatch
dispatch
to
to
the
the
block.
block
We
we
just
just
have
have
one
one
single
single
event
event
with
with
no
no
data
data
payload.
payload
We'll
we'll
define
define
that
that
as
as
the
the
counter
counter
event
event
enum
enum
with
with
one
one
value
value
of
of
increment.
increment
From
from
there,
there
we
we
define
define
the
the
counter
counter
block
block
class
class
and
and
it
it
then's
then's
block
block
which
which
is
is
provided
provided
by
by
the
the
library
library
and
and
we
we
provide
provide
it
it
with
with
our
our
counter
counter
event
event
enum
enum
that
that
we
we
just
just
created.
created
Now,
now
the
the
job
job
of
of
the
the
block
block
is
is
to
to
define
define
the
the
initial
initial
state.
state
This
this
can
can
be
be
your
your
own
own
class,
class
but
but
in
in
our
our
case,
case
it's
it's
just
just
an
an
integer
integer
that
that
starts
starts
at
at
0.
0
The
the
next
next
thing
thing
we
we
do
do
is
is
define
define
a
a
reducer
reducer
function
function
called
called
map
map
event
event
to
to
state.
state
It
it
has
has
the
the
current
current
state
state
as
as
its
its
first
first
argument
argument
and
and
the
the
event
event
as
as
its
its
second
second
argument.
argument
If
if
you've
you've
ever
ever
worked
worked
with
with
Redux
redux
or
or
NGRX,
ngrx
this
this
should
should
look
look
very
very
familiar.
familiar
And
and
you'll
you'll
know
know
the
the
next
next
step
step
is
is
to
to
define
define
a
a
switch
switch
statement
statement
that
that
will
will
look
look
at
at
the
the
event
event
itself
itself
and
and
then
then
determine
determine
how
how
to
to
reduce
reduce
the
the
next
next
state
state
based
based
on
on
that
that
event.
event
So
so
to
to
increment
increment
a
a
counter,
counter
we
we
take
take
the
the
current
current
state
state
and
and
add
add
1
1
to
to
it.
it
And
and
now
now
we're
we're
ready
ready
to
to
build
build
out
out
the
the
actual
actual
Home
home
page
page
UI
ui
widget.
widget
So
so
this
this
will
will
just
just
be
be
a
a
stateless
stateless
widget.
widget
And
and
inside
inside
its
its
build
build
method,
method
it
it
can
can
access
access
the
the
Counter
counter
Block
block
which
which
it
it
does
does
by
by
calling
calling
BlockProvider
blockprovider
of
of
Context
context
along
along
with
with
our
our
Counter
counter
Block
block
type.
type
And
and
that
that
should
should
feel
feel
very
very
natural
natural
to
to
a
a
Flutter
flutter
developer
developer
because
because
you
you
do
do
the
the
same
same
thing
thing
for
for
media
media
queries
queries
and
and
themes
themes
and
and
things
things
like
like
that.
that
At
at
this
this
point,
point
we
we
want
want
to
to
rebuild
rebuild
the
the
UI
ui
when
when
the
the
state
state
of
of
the
the
block
block
changes.
changes
We
we
can
can
do
do
that
that
with
with
a
a
Block
block
Builder.
builder
The
the
Block
block
Builder
builder
is
is
just
just
like
like
a
a
StreamBuilder,
streambuilder
but
but
instead
instead
of
of
a
a
Stream,
stream
it
it
takes
takes
the
the
block
block
as
as
an
an
argument.
argument
Then
then
we
we
can
can
access
access
the
the
current
current
state
state
inside
inside
of
of
this
this
function,
function
which
which
in
in
our
our
case
case
is
is
just
just
the
the
integer
integer
of
of
the
the
counter.
counter
When
when
it
it
comes
comes
to
to
changing
changing
the
the
state,
state
we
we
don't
don't
actually
actually
mutate
mutate
the
the
state
state
directly
directly
like
like
we
we
have
have
in
in
previous
previous
examples.
examples
Instead,
instead
we
we
dispatch
dispatch
an
an
action
action
to
to
the
the
block.
block
And
and
I
i
really
really
like
like
this
this
approach
approach
because
because
it
it
separates
separates
all
all
of
of
our
our
business
business
logic
logic
from
from
the
the
widget,
widget
which
which
is
is
now
now
only
only
concerned
concerned
with
with
rendering
rendering
the
the
UI
ui
and
and
dispatching
dispatching
actions.
actions
So
so
it
it
obviously
obviously
took
took
a
a
little
little
more
more
code
code
to
to
get
get
to
to
this
this
point,
point
but
but
the
the
block
block
pattern
pattern
is
is
a
a
solid
solid
state
state
management
management
solution
solution
that
that
can
can
pay
pay
off
off
in
in
the
the
long
long
run.
run
Now,
now
I
i
don't
don't
know
know
if
if
you've
you've
been
been
keeping
keeping
count,
count
but
but
I
i
promised
promised
you
you
10
10
different
different
state
state
management
management
Solutions.
solutions
So
so
far,
far
we've
we've
only
only
covered
covered
5,
5
but
but
there
there
are
are
5
5
more
more
that
that
you
you
should
should
definitely
definitely
know
know
about
about
before
before
making
making
any
any
big
big
decisions.
decisions
The
the
godfather
godfather
of
of
all
all
this
this
state
state
management
management
stuff
stuff
is
is
Redux,
redux
which
which
has
has
been
been
the
the
de
de
facto
facto
state
state
management
management
library
library
from
from
the
the
React
react
world,
world
but
but
is
is
also
also
available
available
in
in
Flutter.
flutter
It
it
follows
follows
a
a
lot
lot
of
of
the
the
same
same
concepts
concepts
that
that
we
we
just
just
looked
looked
at
at
in
in
the
the
block
block
pattern.
pattern
But
but
usually,
usually
you
you
have
have
a
a
single
single
store
store
provider
provider
for
for
the
the
entire
entire
app,
app
and
and
then
then
you
you
connect
connect
that
that
store
store
to
to
different
different
widgets
widgets
where
where
it's
it's
needed.
needed
If
if
you're
you're
brand
brand
new
new
to
to
state
state
management,
management
I
i
would
would
probably
probably
recommend
recommend
going
going
straight
straight
to
to
block.
block
But
but
if
if
you're
you're
already
already
experienced
experienced
with
with
Redux,
redux
this
this
is
is
definitely
definitely
something
something
you'd
you'd
wanna
wanna
check
check
out.
out
There's
there's
another
another
library
library
that
that
recently
recently
became
became
available
available
in
in
Flutter
flutter
that
that
also
also
comes
comes
from
from
the
the
React
react
world,
world
MobX.
mobx
It
it
follows
follows
a
a
lot
lot
of
of
the
the
same
same
principles
principles
as
as
Redux
redux
and
and
Block,
block
but
but
provides
provides
some
some
extra
extra
abstractions
abstractions
that
that
I
i
think
think
make
make
the
the
process
process
a
a
little
little
more
more
developer
developer
friendly.
friendly
And
and
one
one
thing
thing
that's
that's
cool
cool
is
is
that
that
it
it
has
has
a
a
CodeGen
codegen
package
package
that
that
you
you
can
can
use
use
to
to
eliminate
eliminate
a
a
lot
lot
of
of
the
the
boilerplate
boilerplate
code.
code
That
that
can
can
be
be
very
very
useful
useful
if
if
you
you
want
want
to
to
apply
apply
these
these
powerful
powerful
state
state
management
management
patterns,
patterns
but
but
have
have
a
a
small
small
team,
team
or
or
maybe
maybe
you're
you're
just
just
prototyping
prototyping
out
out
some
some
ideas
ideas
quickly.
quickly
Now
now
MobX,
mobx
Redux,
redux
and
and
Block
block
are
are
all
all
state
state
management
management
libraries
libraries
that
that
I
i
would
would
consider
consider
pretty
pretty
heavyweight
heavyweight
that
that
require
require
a
a
lot
lot
of
of
explicit
explicit
code.
code
If
if
you
you
just
just
want
want
to
to
change
change
some
some
data
data
and
and
pass
pass
it
it
around
around
the
the
widget
widget
tree,
tree
then
then
you
you
should
should
check
check
out
out
scoped
scoped
model.
model
This
this
is
is
the
the
state
state
management
management
approach
approach
that
that
they
they
describe
describe
in
in
the
the
official
official
documentation.
documentation
And
and
like
like
a
a
lot
lot
of
of
the
the
other
other
things
things
we've
we've
looked
looked
at,
at
it
it
uses
uses
an
an
inherited
inherited
widget
widget
to
to
pass
pass
state
state
around
around
the
the
free.
free
But
but
in
in
this
this
version,
version
you
you
don't
don't
have
have
to
to
write
write
your
your
own
own
reducer
reducer
functions
functions
or
or
actions
actions
or
or
any
any
other
other
boilerplate
boilerplate
code.
code
Basically,
basically
you
you
just
just
define
define
your
your
data
data
and
and
your
your
mutations
mutations
inside
inside
of
of
a
a
model,
model
then
then
you
you
scope
scope
that
that
model
model
somewhere
somewhere
in
in
the
the
widget
widget
tree.
tree
And
and
then
then
you
you
have
have
a
a
builder
builder
that
that
can
can
rebuild
rebuild
the
the
UI
ui
when
when
that
that
model
model
changes.
changes
So
so
it's
it's
a
a
relatively
relatively
simple
simple
way
way
to
to
deal
deal
with
with
shared
shared
state.
state
The
the
next
next
package
package
on
on
this
this
list
list
is
is
one
one
I
i
haven't
haven't
actually
actually
used
used
yet,
yet
but
but
that
that
looks
looks
very
very
promising,
promising
Flutter
flutter
Hooks.
hooks
I
i
have
have
used
used
hooks
hooks
in
in
React
react
JS
js
and
and
they
they
definitely
definitely
improve
improve
productivity
productivity
and
and
also
also
code
code
reusability.
reusability
This
this
example
example
from
from
the
the
docs
docs
has
has
a
a
useReducer
usereducer
hook,
hook
and
and
you
you
can
can
see
see
that
that
hook
hook
sets
sets
up
up
a
a
lot
lot
of
of
the
the
things
things
that
that
we'd
we'd
have
have
to
to
do
do
manually
manually
like
like
the
the
state
state
and
and
the
the
action
action
dispatching.
dispatching
So
so
that's
that's
a
a
really
really
nice
nice
alternative
alternative
to
to
the
the
Stateful
stateful
Widget
widget
or
or
some
some
of
of
the
the
other
other
approaches
approaches
that
that
we
we
looked
looked
at
at
for
for
local
local
state.
state
The
the
last
last
item
item
on
on
this
this
list
list
is
is
one
one
you
you
might
might
not
not
expect,
expect
Firebase.
firebase
What
what
a
a
lot
lot
of
of
people
people
don't
don't
realize
realize
is
is
that
that
Firebase
firebase
is
is
already
already
a
a
state
state
management
management
system
system
that
that
is
is
way
way
more
more
advanced
advanced
than
than
anything
anything
you're
you're
going
going
to
to
build.
build
It
it
may
may
not
not
be
be
a
a
solution
solution
for
for
every
every
state
state
management
management
need,
need
but
but
it
it
can
can
handle
handle
some
some
of
of
the
the
most
most
advanced
advanced
aspects
aspects
of
of
state
state
management
management
like
like
user
user
authentication,
authentication
persisting
persisting
data
data
to
to
a
a
back
back
end
end
database,
database
remote
remote
config,
config
file
file
uploads,
uploads
and
and
the
the
list
list
goes
goes
on.
on
The
the
Firebase
firebase
SDK
sdk
exposes
exposes
everything
everything
as
as
streams
streams
or
or
futures
futures
which
which
is
is
exactly
exactly
what
what
you
you
want
want
with
with
a
a
reactive
reactive
framework
framework
like
like
Flutter.
flutter
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
If
if
I
i
missed
missed
anything,
anything
please
please
let
let
me
me
know
know
in
in
the
the
comments.
comments
And
and
if
if
you
you
want
want
to
to
support
support
this
this
channel
channel
and
and
get
get
access
access
to
to
even
even
more
more
content,
content
consider
consider
becoming
becoming
a
a
Pro
pro
Member
member
at
at
Fireship
fireship
IO.
io
Thanks
thanks
for
for
watching
watching
and
and
I
i
will
will
talk
talk
to
to
you
you
soon.
soon
success
The speakers discuss the benefits of state management in building basic counter apps, including the use of different strategies and mistakes, and the process of creating a Stateful Doctor. They also show personal favorite ways to manage global state in Flutter app, including using a personal favorite way to manage global state and the use of a unique build function. The speakers recommend various state management libraries and suggest using a single store provider for the entire app, as well as becoming a Pro member at Fireship IO. They also mention the use of a new library called MobX for state management and recommend becoming a Pro member at Fireship IO.
Flutter State Management - The Grand Tour
State management, for whatever reason, is a topic that brings out strong opinions and developers. Oh. Yeah. Um, I'm gonna have To go ahead and sort of disagree with you there. In today's video, we'll look at 10 different ways to build a basic counter app using different state management strategies in Flutter. We'll also just talk about what state management is, and why there are so many different ways to approach it. And hopefully by the end of this video, you'll know exactly which strategy is ideal for your If you're new here, like and subscribe, and you can grab a full source code on Fireship IO. And, I'm giving away another t shirt with this video. Just leave me a comment with your own opinions about state management Woah. First of all, what is state? In a reactive framework like Flutter, you can think of your UI as the return value of a function. That function gets called with one argument, which is your state. So state is just data that changes over the life cycle of your app. A lot of your data can be self contained within a single widget. That's known as Local State. We'll look at the tools that we have built into Flutter to manage local state, which is pretty straightforward. Things get interesting when we start talking about global state or state that needs to be shared throughout the widget tree. Coming from the web development world, I've seen tons of debate over state management and a lot of apps over engineered with these big state management libraries that didn't really need them. That's not to say they're not valuable, but even the creators and maintainers of those libraries will tell you that you probably don't need them. We'll talk about the pros and cons of these various libraries as we go, but for now let's focus on the fundamental building blocks in Flutter, starting with the stateful widget. When you run flutter create from the command line, it gives you some starter code that increments a counter with a stateful widget. We're going to rebuild this counter multiple times throughout this video using different state management strategies. To create a StatefulWidget, we need 2 classes. The first one is the StatefulWidget itself and that implements a create state method. And that returns our second class which is an extension of the State class. And this is where all the heavy lifting happens. 1st, we define a property called counter, which is an integer that defines the actual data state of this widget. Then we define a method called increment counter and it calls a method called set state which will tell this widget to rerender when this value changes. After that, we implement the build function which defines the actual widgets that will be rebuilt every time set state is called. I've stripped these down to the bare minimum. We just have a text widget that will display the current value of the counter and we have a floating action button that will increment the counter when pressed. Stateful widgets are great for managing local state, but there's a couple things I don't like here. First of all, we have to define 2 separate classes which is sort of confusing and adds boilerplate. And I know from experience with React JS that calling setState all over the place does not scale very well. It's fine when we just have one property, but you can imagine how this would become a mess if we had 20 different properties on widget to update. And with that, I'll move on to topic number 2, Stateful Builder. There's a variety of different builder widgets in Flutter that allow you to react to different types of changes. One of those is Stateful Builder which will allow us to simplify our stateful widget code. Notice this time we're starting by extending a stateless widget and then we'll define our state as a counter that starts at 0. Then the first widget that we'll add to our build method is a Stateful Builder and that takes a builder function. That function gives us access to the build context and also a function called set state. When we call set state, it will tell the Stateful Builder to rebuild all the widgets inside this function. And they'll look pretty much identical to the previous example where we have text for the counter value and then a floating action button to increment it. Now I want to point out that I'm kind of breaking the rules in Flutter. That's why you see this green squiggly line under the class name. This class is immutable, which means the properties on it should never be reassigned, and we're violating that by incrementing the counter. So if you use a Stateful Builder within a Stateless Widget, I would recommend setting up your data as a map or a list because you can mutate values in those data structures without breaking the contract of the Stateless widget. But, overall, the Stateful Builder is a nice little tool that helps you avoid the boilerplate of a Stateful widget and is really ideal when you have simple local state management to deal with. But now things are going to start getting interesting because we're going to talk about app state or global state. In Flutter, it's possible to pass data from top to bottom or from parent to child, but it's not really practical to pass data the other way around from child back to parent or from sibling to sibling. But almost every non trivial app is going to have some kind of shared stayed at one point or another that runs into this limitation. The first thing I wanna show you is inherited widget. Now I don't recommend using this as a state management solution because there are better alternatives that already do for you, but it's important to know how it works because it's a fundamental building block in Flutter that's implemented in many other features of the framework. Basically, it's a widget that allows you to pass context to any of its descendants no matter how far nested they are in the widget tree. So the first thing you'll usually do is put the inherited widget towards the top of the widget tree, which we've done here with our inherited counter, and then we have our actual home page as a child of that inherited widget. Our inherited counter will extend the inherited widget built into Flutter, then it will take a child widget as an argument to its constructor. From there, we're going to override a method called update should notify, and this will run when this inherited widget is rebuilt and will notify any descendants whether or not they need to rebuild. I'm just setting it to true, but you could look at the diff between the old and the new data to determine whether or not the widget actually needs to rerender. And then it's conventional to also implement a static method called of then calls inherit from widget of exact type with the inherited counter type. Now the inherited widget is immutable, so we could wrap it in a stateful widget to tell it when to rebuild. But for the sake of simplicity, I'll just go ahead and define our counter data as a map. This is a private variable. So first we'll go ahead and define an increment method which allows us to increment the counter value, and then we'll add a getter to get the current value from the map. Now that we have that set up, we can go down here and define our stateless widget home page. Now just for convenience, I'm using the example we had set up previously with our stateful builder. And inside that builder method, we can access the value from the inherited counter by calling of context with the values from that class. Now, this may look trivial in this example, but if you imagine our home page was nested 20 levels deep, it could still access these values without having to directly pass anything through each constructor are in the widget tree. Now like I said earlier, you probably don't need to mess with inherited widgets directly and you'll see why later in this video because there's already libraries that do similar things in a much plus awkward way. But before we get to that point, I want to show you my personal favorite way to manage global state in a Flutter app, and that is to leverage a special type of stream in RxDart called a behavior subject. We'll start by creating our own custom class and then give it a private value that's set to a behavior subject that starts at 0. These are incredibly useful for state management for a variety of reasons. First of all, they always have a current value that we can read in Flutter's build methods. But at the same time we can treat them as a stream and a stream that we can control by adding new values to it. And it's a broadcast stream by default, so multiple widgets can listen to the same stream. This allows us to implement our own business logic related to the flow of data for the stream. And we can do it completely independent of the widget tree. That makes it much easier to test in isolation and also just easier to reason about. Now we can define our own custom API that our widgets can consume. For example, if we want to expose the stream, we can just call counter stream. Then we can also create a getter that grabs the current value synchronously from the behavior subject, and and then we'll define a method to mutate the behavior subject called increment, which just adds a new value to the stream. And that's basically all it takes to build your own custom state management solution that all of your widgets can react to and share. Now I'm going to just instantiate it in the global namespace, which is kind of frowned upon, but I'll show you an alternative to this in just a minute. Now that we have access to this counter service globally, we can rebuild that home page widget. In the build method, we'll start with a scaffold, and then as the body, we'll add a stream builder. Then we'll pass it the stream from our behavior subject. So now every time we add a new value to the behavior subject, this widget will rebuild. And one minor thing that you might have missed is that we're able to nest the StreamBuilder deeper in the widget tree, and that means we're repainting less of the UI than we were in previous examples. It's not a big deal here, but it could be if you have a lot of widgets nested in the Scaffold. The next thing we'll do is implement the builder function. For that, we'll just return our text and that will have a snapshot of the current count or the current data from the Stream. And the actual Cetera of that data is completely decoupled from the Stream Builder, which means we can add it outside of the build context so it doesn't need to rebuild whenever the actual value of the stream changes. And another bonus of a StreamBuilder is that it will automatically unsubscribe from the stream when the widget is disposed. That means you don't need to manually cancel streams to avoid memory leaks. This is really nice and flexible, but I'd like to get this out of the global namespace and use it in a way that's more like a true singleton. For that, I'm going to register it with a library called GetIt. We'll go ahead and import that library and then instantiate get it. Then we'll go into our main function and call register singleton, pass in the type counter, and then instantiate the counter. Now we can use our counter state in any widget that requires it. This makes the state easier to mock for integration tests and guarantees that you won't accidentally instantiate the counter class more than once. If you're an Angular developer, I definitely think you'll like this pattern. But now it's time to move on to the next strategy, the block pattern. Now we could implement this entirely from Gratch, but I highly recommend using the Flutter block library. Under the hood, it extends the inherited widget that we looked at earlier, but it provides a much more intuitive way to pass state around the widget tree. Block is very similar to Redux if you've ever worked with React. It provides a very explicit one way data flow that we can break down into 3 steps. There's an event such as the user clicking on a button. That event gets dispatched to a block, and then it will reduce the next state and emit it out as a stream so we can use it in StreamBuilder just like we did in the previous example. The first thing we'll do is install block and Flutter block, then import them in this file. Then we'll add the block provider to the root of the application. The BlockProvider itself actually extends inherited widget and it takes a block type which we'll define in the next step. All descendants of this widget will be able to access state or the data contained inside this block. Now the next thing we need to do is define the actions or the events that the user can dispatch to the block. We just have one single event with no data payload. We'll define that as the counter event enum with one value of increment. From there, we define the counter block class and it then's block which is provided by the library and we provide it with our counter event enum that we just created. Now, the job of the block is to define the initial state. This can be your own class, but in our case, it's just an integer that starts at 0. The next thing we do is define a reducer function called map event to state. It has the current state as its first argument and the event as its second argument. If you've ever worked with Redux or NGRX, this should look very familiar. And you'll know the next step is to define a switch statement that will look at the event itself and then determine how to reduce the next state based on that event. So to increment a counter, we take the current state and add 1 to it. And now we're ready to build out the actual Home page UI widget. So this will just be a stateless widget. And inside its build method, it can access the Counter Block which it does by calling BlockProvider of Context along with our Counter Block type. And that should feel very natural to a Flutter developer because you do the same thing for media queries and themes and things like that. At this point, we want to rebuild the UI when the state of the block changes. We can do that with a Block Builder. The Block Builder is just like a StreamBuilder, but instead of a Stream, it takes the block as an argument. Then we can access the current state inside of this function, which in our case is just the integer of the counter. When it comes to changing the state, we don't actually mutate the state directly like we have in previous examples. Instead, we dispatch an action to the block. And I really like this approach because it separates all of our business logic from the widget, which is now only concerned with rendering the UI and dispatching actions. So it obviously took a little more code to get to this point, but the block pattern is a solid state management solution that can pay off in the long run. Now, I don't know if you've been keeping count, but I promised you 10 different state management Solutions. So far, we've only covered 5, but there are 5 more that you should definitely know about before making any big decisions. The godfather of all this state management stuff is Redux, which has been the de facto state management library from the React world, but is also available in Flutter. It follows a lot of the same concepts that we just looked at in the block pattern. But usually, you have a single store provider for the entire app, and then you connect that store to different widgets where it's needed. If you're brand new to state management, I would probably recommend going straight to block. But if you're already experienced with Redux, this is definitely something you'd wanna check out. There's another library that recently became available in Flutter that also comes from the React world, MobX. It follows a lot of the same principles as Redux and Block, but provides some extra abstractions that I think make the process a little more developer friendly. And one thing that's cool is that it has a CodeGen package that you can use to eliminate a lot of the boilerplate code. That can be very useful if you want to apply these powerful state management patterns, but have a small team, or maybe you're just prototyping out some ideas quickly. Now MobX, Redux, and Block are all state management libraries that I would consider pretty heavyweight that require a lot of explicit code. If you just want to change some data and pass it around the widget tree, then you should check out scoped model. This is the state management approach that they describe in the official documentation. And like a lot of the other things we've looked at, it uses an inherited widget to pass state around the free. But in this version, you don't have to write your own reducer functions or actions or any other boilerplate code. Basically, you just define your data and your mutations inside of a model, then you scope that model somewhere in the widget tree. And then you have a builder that can rebuild the UI when that model changes. So it's a relatively simple way to deal with shared state. The next package on this list is one I haven't actually used yet, but that looks very promising, Flutter Hooks. I have used hooks in React JS and they definitely improve productivity and also code reusability. This example from the docs has a useReducer hook, and you can see that hook sets up a lot of the things that we'd have to do manually like the state and the action dispatching. So that's a really nice alternative to the Stateful Widget or some of the other approaches that we looked at for local state. The last item on this list is one you might not expect, Firebase. What a lot of people don't realize is that Firebase is already a state management system that is way more advanced than anything you're going to build. It may not be a solution for every state management need, but it can handle some of the most advanced aspects of state management like user authentication, persisting data to a back end database, remote config, file uploads, and the list goes on. The Firebase SDK exposes everything as streams or futures which is exactly what you want with a reactive framework like Flutter. I'm gonna go ahead and wrap things up there. If I missed anything, please let me know in the comments. And if you want to support this channel and get access to even more content, consider becoming a Pro Member at Fireship IO. Thanks for watching and I will talk to you soon.
The speakers discuss the benefits of state management in building basic counter apps, including the use of different strategies and mistakes, and the process of creating a Stateful Doctor. They also show personal favorite ways to manage global state in Flutter app, including using a personal favorite way to manage global state and the use of a unique build function. The speakers recommend various state management libraries and suggest using a single store provider for the entire app, as well as becoming a Pro member at Fireship IO. They also mention the use of a new library called MobX for state management and recommend becoming a Pro member at Fireship IO.

        [INST]
        You are youtuber called Fireship you make engaging high-intensity and entertaining coding tutorials and tech news. 
        you covers a wide range of topics relevant to programmers, aiming to help them learn and improve their skills quickly.
        
        Given the title of the video : Flutter State Management - The Grand Tour 
        and a small summary : The speakers discuss the benefits of state management in building basic counter apps, including the use of different strategies and mistakes, and the process of creating a Stateful Doctor. They also show personal favorite ways to manage global state in Flutter app, including using a personal favorite way to manage global state and the use of a unique build function. The speakers recommend various state management libraries and suggest using a single store provider for the entire app, as well as becoming a Pro member at Fireship IO. They also mention the use of a new library called MobX for state management and recommend becoming a Pro member at Fireship IO.
        [/INST]
        
        Generate the video : State management, for whatever reason, is a topic that brings out strong opinions and developers. Oh. Yeah. Um, I'm gonna have To go ahead and sort of disagree with you there. In today's video, we'll look at 10 different ways to build a basic counter app using different state management strategies in Flutter. We'll also just talk about what state management is, and why there are so many different ways to approach it. And hopefully by the end of this video, you'll know exactly which strategy is ideal for your If you're new here, like and subscribe, and you can grab a full source code on Fireship IO. And, I'm giving away another t shirt with this video. Just leave me a comment with your own opinions about state management Woah. First of all, what is state? In a reactive framework like Flutter, you can think of your UI as the return value of a function. That function gets called with one argument, which is your state. So state is just data that changes over the life cycle of your app. A lot of your data can be self contained within a single widget. That's known as Local State. We'll look at the tools that we have built into Flutter to manage local state, which is pretty straightforward. Things get interesting when we start talking about global state or state that needs to be shared throughout the widget tree. Coming from the web development world, I've seen tons of debate over state management and a lot of apps over engineered with these big state management libraries that didn't really need them. That's not to say they're not valuable, but even the creators and maintainers of those libraries will tell you that you probably don't need them. We'll talk about the pros and cons of these various libraries as we go, but for now let's focus on the fundamental building blocks in Flutter, starting with the stateful widget. When you run flutter create from the command line, it gives you some starter code that increments a counter with a stateful widget. We're going to rebuild this counter multiple times throughout this video using different state management strategies. To create a StatefulWidget, we need 2 classes. The first one is the StatefulWidget itself and that implements a create state method. And that returns our second class which is an extension of the State class. And this is where all the heavy lifting happens. 1st, we define a property called counter, which is an integer that defines the actual data state of this widget. Then we define a method called increment counter and it calls a method called set state which will tell this widget to rerender when this value changes. After that, we implement the build function which defines the actual widgets that will be rebuilt every time set state is called. I've stripped these down to the bare minimum. We just have a text widget that will display the current value of the counter and we have a floating action button that will increment the counter when pressed. Stateful widgets are great for managing local state, but there's a couple things I don't like here. First of all, we have to define 2 separate classes which is sort of confusing and adds boilerplate. And I know from experience with React JS that calling setState all over the place does not scale very well. It's fine when we just have one property, but you can imagine how this would become a mess if we had 20 different properties on widget to update. And with that, I'll move on to topic number 2, Stateful Builder. There's a variety of different builder widgets in Flutter that allow you to react to different types of changes. One of those is Stateful Builder which will allow us to simplify our stateful widget code. Notice this time we're starting by extending a stateless widget and then we'll define our state as a counter that starts at 0. Then the first widget that we'll add to our build method is a Stateful Builder and that takes a builder function. That function gives us access to the build context and also a function called set state. When we call set state, it will tell the Stateful Builder to rebuild all the widgets inside this function. And they'll look pretty much identical to the previous example where we have text for the counter value and then a floating action button to increment it. Now I want to point out that I'm kind of breaking the rules in Flutter. That's why you see this green squiggly line under the class name. This class is immutable, which means the properties on it should never be reassigned, and we're violating that by incrementing the counter. So if you use a Stateful Builder within a Stateless Widget, I would recommend setting up your data as a map or a list because you can mutate values in those data structures without breaking the contract of the Stateless widget. But, overall, the Stateful Builder is a nice little tool that helps you avoid the boilerplate of a Stateful widget and is really ideal when you have simple local state management to deal with. But now things are going to start getting interesting because we're going to talk about app state or global state. In Flutter, it's possible to pass data from top to bottom or from parent to child, but it's not really practical to pass data the other way around from child back to parent or from sibling to sibling. But almost every non trivial app is going to have some kind of shared stayed at one point or another that runs into this limitation. The first thing I wanna show you is inherited widget. Now I don't recommend using this as a state management solution because there are better alternatives that already do for you, but it's important to know how it works because it's a fundamental building block in Flutter that's implemented in many other features of the framework. Basically, it's a widget that allows you to pass context to any of its descendants no matter how far nested they are in the widget tree. So the first thing you'll usually do is put the inherited widget towards the top of the widget tree, which we've done here with our inherited counter, and then we have our actual home page as a child of that inherited widget. Our inherited counter will extend the inherited widget built into Flutter, then it will take a child widget as an argument to its constructor. From there, we're going to override a method called update should notify, and this will run when this inherited widget is rebuilt and will notify any descendants whether or not they need to rebuild. I'm just setting it to true, but you could look at the diff between the old and the new data to determine whether or not the widget actually needs to rerender. And then it's conventional to also implement a static method called of then calls inherit from widget of exact type with the inherited counter type. Now the inherited widget is immutable, so we could wrap it in a stateful widget to tell it when to rebuild. But for the sake of simplicity, I'll just go ahead and define our counter data as a map. This is a private variable. So first we'll go ahead and define an increment method which allows us to increment the counter value, and then we'll add a getter to get the current value from the map. Now that we have that set up, we can go down here and define our stateless widget home page. Now just for convenience, I'm using the example we had set up previously with our stateful builder. And inside that builder method, we can access the value from the inherited counter by calling of context with the values from that class. Now, this may look trivial in this example, but if you imagine our home page was nested 20 levels deep, it could still access these values without having to directly pass anything through each constructor are in the widget tree. Now like I said earlier, you probably don't need to mess with inherited widgets directly and you'll see why later in this video because there's already libraries that do similar things in a much plus awkward way. But before we get to that point, I want to show you my personal favorite way to manage global state in a Flutter app, and that is to leverage a special type of stream in RxDart called a behavior subject. We'll start by creating our own custom class and then give it a private value that's set to a behavior subject that starts at 0. These are incredibly useful for state management for a variety of reasons. First of all, they always have a current value that we can read in Flutter's build methods. But at the same time we can treat them as a stream and a stream that we can control by adding new values to it. And it's a broadcast stream by default, so multiple widgets can listen to the same stream. This allows us to implement our own business logic related to the flow of data for the stream. And we can do it completely independent of the widget tree. That makes it much easier to test in isolation and also just easier to reason about. Now we can define our own custom API that our widgets can consume. For example, if we want to expose the stream, we can just call counter stream. Then we can also create a getter that grabs the current value synchronously from the behavior subject, and and then we'll define a method to mutate the behavior subject called increment, which just adds a new value to the stream. And that's basically all it takes to build your own custom state management solution that all of your widgets can react to and share. Now I'm going to just instantiate it in the global namespace, which is kind of frowned upon, but I'll show you an alternative to this in just a minute. Now that we have access to this counter service globally, we can rebuild that home page widget. In the build method, we'll start with a scaffold, and then as the body, we'll add a stream builder. Then we'll pass it the stream from our behavior subject. So now every time we add a new value to the behavior subject, this widget will rebuild. And one minor thing that you might have missed is that we're able to nest the StreamBuilder deeper in the widget tree, and that means we're repainting less of the UI than we were in previous examples. It's not a big deal here, but it could be if you have a lot of widgets nested in the Scaffold. The next thing we'll do is implement the builder function. For that, we'll just return our text and that will have a snapshot of the current count or the current data from the Stream. And the actual Cetera of that data is completely decoupled from the Stream Builder, which means we can add it outside of the build context so it doesn't need to rebuild whenever the actual value of the stream changes. And another bonus of a StreamBuilder is that it will automatically unsubscribe from the stream when the widget is disposed. That means you don't need to manually cancel streams to avoid memory leaks. This is really nice and flexible, but I'd like to get this out of the global namespace and use it in a way that's more like a true singleton. For that, I'm going to register it with a library called GetIt. We'll go ahead and import that library and then instantiate get it. Then we'll go into our main function and call register singleton, pass in the type counter, and then instantiate the counter. Now we can use our counter state in any widget that requires it. This makes the state easier to mock for integration tests and guarantees that you won't accidentally instantiate the counter class more than once. If you're an Angular developer, I definitely think you'll like this pattern. But now it's time to move on to the next strategy, the block pattern. Now we could implement this entirely from Gratch, but I highly recommend using the Flutter block library. Under the hood, it extends the inherited widget that we looked at earlier, but it provides a much more intuitive way to pass state around the widget tree. Block is very similar to Redux if you've ever worked with React. It provides a very explicit one way data flow that we can break down into 3 steps. There's an event such as the user clicking on a button. That event gets dispatched to a block, and then it will reduce the next state and emit it out as a stream so we can use it in StreamBuilder just like we did in the previous example. The first thing we'll do is install block and Flutter block, then import them in this file. Then we'll add the block provider to the root of the application. The BlockProvider itself actually extends inherited widget and it takes a block type which we'll define in the next step. All descendants of this widget will be able to access state or the data contained inside this block. Now the next thing we need to do is define the actions or the events that the user can dispatch to the block. We just have one single event with no data payload. We'll define that as the counter event enum with one value of increment. From there, we define the counter block class and it then's block which is provided by the library and we provide it with our counter event enum that we just created. Now, the job of the block is to define the initial state. This can be your own class, but in our case, it's just an integer that starts at 0. The next thing we do is define a reducer function called map event to state. It has the current state as its first argument and the event as its second argument. If you've ever worked with Redux or NGRX, this should look very familiar. And you'll know the next step is to define a switch statement that will look at the event itself and then determine how to reduce the next state based on that event. So to increment a counter, we take the current state and add 1 to it. And now we're ready to build out the actual Home page UI widget. So this will just be a stateless widget. And inside its build method, it can access the Counter Block which it does by calling BlockProvider of Context along with our Counter Block type. And that should feel very natural to a Flutter developer because you do the same thing for media queries and themes and things like that. At this point, we want to rebuild the UI when the state of the block changes. We can do that with a Block Builder. The Block Builder is just like a StreamBuilder, but instead of a Stream, it takes the block as an argument. Then we can access the current state inside of this function, which in our case is just the integer of the counter. When it comes to changing the state, we don't actually mutate the state directly like we have in previous examples. Instead, we dispatch an action to the block. And I really like this approach because it separates all of our business logic from the widget, which is now only concerned with rendering the UI and dispatching actions. So it obviously took a little more code to get to this point, but the block pattern is a solid state management solution that can pay off in the long run. Now, I don't know if you've been keeping count, but I promised you 10 different state management Solutions. So far, we've only covered 5, but there are 5 more that you should definitely know about before making any big decisions. The godfather of all this state management stuff is Redux, which has been the de facto state management library from the React world, but is also available in Flutter. It follows a lot of the same concepts that we just looked at in the block pattern. But usually, you have a single store provider for the entire app, and then you connect that store to different widgets where it's needed. If you're brand new to state management, I would probably recommend going straight to block. But if you're already experienced with Redux, this is definitely something you'd wanna check out. There's another library that recently became available in Flutter that also comes from the React world, MobX. It follows a lot of the same principles as Redux and Block, but provides some extra abstractions that I think make the process a little more developer friendly. And one thing that's cool is that it has a CodeGen package that you can use to eliminate a lot of the boilerplate code. That can be very useful if you want to apply these powerful state management patterns, but have a small team, or maybe you're just prototyping out some ideas quickly. Now MobX, Redux, and Block are all state management libraries that I would consider pretty heavyweight that require a lot of explicit code. If you just want to change some data and pass it around the widget tree, then you should check out scoped model. This is the state management approach that they describe in the official documentation. And like a lot of the other things we've looked at, it uses an inherited widget to pass state around the free. But in this version, you don't have to write your own reducer functions or actions or any other boilerplate code. Basically, you just define your data and your mutations inside of a model, then you scope that model somewhere in the widget tree. And then you have a builder that can rebuild the UI when that model changes. So it's a relatively simple way to deal with shared state. The next package on this list is one I haven't actually used yet, but that looks very promising, Flutter Hooks. I have used hooks in React JS and they definitely improve productivity and also code reusability. This example from the docs has a useReducer hook, and you can see that hook sets up a lot of the things that we'd have to do manually like the state and the action dispatching. So that's a really nice alternative to the Stateful Widget or some of the other approaches that we looked at for local state. The last item on this list is one you might not expect, Firebase. What a lot of people don't realize is that Firebase is already a state management system that is way more advanced than anything you're going to build. It may not be a solution for every state management need, but it can handle some of the most advanced aspects of state management like user authentication, persisting data to a back end database, remote config, file uploads, and the list goes on. The Firebase SDK exposes everything as streams or futures which is exactly what you want with a reactive framework like Flutter. I'm gonna go ahead and wrap things up there. If I missed anything, please let me know in the comments. And if you want to support this channel and get access to even more content, consider becoming a Pro Member at Fireship IO. Thanks for watching and I will talk to you soon.
        