Over the last 6 years of being active with Flutter I’ve seen lots of solutions to the same problem.
- MobX
- Provider
- Riverpod
- ScopedModel
- bloc
- watch_it
- Redux
The fun part is that you can make any of these solutions work but what I ended up learning is that you probably shouldn’t.
The downsides of state management packages
Before we dive into how I solve this issue, I would like to talk a bit about the downsides of using large dependencies to solve the issue around “state”.
- You have dependency that is usually tightly coupled with your entire application. Meaning if you ever need to migrate to another solution it’s going to be tough.
- Major changes of the dependency could lead to high work load to make sure your application is using the new approach of that specific dependency. As of writing this a lot of the packages are version 8 and above.
- Not all apps becomes enterprise sized, so the added overhead in smaller apps might impact speed.
- Some of these packages require special testing solutions to confidently test your codebase
- Steep learning curves comes with different solutions. A person well versed in Riverpod is not well versed in bloc.
So what is the solution?
The solution is already part of the framework, it’s mainly a matter of how and what approach you want or should take.
Depending on how you look at it there are upsides and downsides to not having clear recommendations but because of that I will give my recommendations.
First, let’s break down what is required from the concept of “state management”.
Some kind of state should mark the widget as dirty and rebuild.
The most clear cut example of this is using setState
, though as we all know this is not a scalable approach to building out your state management approach.
There are two different types though.
Ephemeral state
Use this as much as possible, make components that can handle their own state. In essence, the state is self contained.
Some examples of this:
- A button should be able to block multiple taps if an async call is in action.
- The progress of a specific animation that can also be reused
App state
There are currently two main approaches (if we ignore streams)
ChangeNotifier
and ValueNotifier
, both these have builder widgets that will cause rebuilds when any of these require state changes to happen.
To provide data throughout your applications there are InheritedWidget
and Service locators
use whatever you like the most.
For every page you have a View Model, that view models contains the state of that page and notifies whenever something is dirty and needs a rebuild. You can use ChangeNotifier
or ValueNotifier
where I prefer the latter.
What I do
app wide services is again simple classes provided throughout the application life-cycle that I personally use ValueNotifier
’s for and a service locator.
Let me provide a simple example
I just want to mention that I go much further into this in the “best flutter course on the internet” that me and Tadas have created. But I will provide examples here as well!
Want to learn Flutter?
We teach you all you need to confidently build apps at hungrimind.com/learn/flutter
The most simple example I could create for the demonstration would be a “counter feature”.
- CounterPage initializes and hold a reference to
CounterPageViewModel
CounterPageViewModel
contains aValueNotifier<int> counterNotifier
and relevant methods to increment and decrement
- The page uses a
ValueListenableBuilder
to react to thecounterNotifier
if you have other app wide service you dependency inject those with either InheritedWidget
or a Service Locator
.
This means that view models doesn’t need to be provided with InheritedWidget
or similar, you would just pass it down the tree as pages usually have a limited depth.
This is fully scalable
This approach is fully scalable, doesn’t rely on large dependencies and anyone that use Flutter can understand without much ramp up time.
To summarize
- Use Ephemeral state as much as possible
- Use
ChangeNotifier
orValueNotifiers
- Use different
ListenableBuilders
depending on the notifier - Keep it simple
You don’t need to complicate your setup even if you want to scale to multiple hundred thousand lines (or even millions).
Get articles right in your inbox
No spam, unsubscribe anytime. We treat your inbox with respect.