State Management With Provider
The Flutter team recommends several state management packages and libraries. Provider is one of the simplest to update your UI when the app state changes. By Michael Katz.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
State Management With Provider
30 mins
Inspecting Provider Widgets
As a quick aside, since the Provider
s are Widgets, you can inspect them in the Flutter Inspector as part of the Widget Tree. In Android Studio, it's accessed from the View ▸ Tool Windows ▸ Flutter Inspector menu.
As you can see from the resulting widget tree, MultiProvider
nests its providers
array as children within each other, in order. Thus, it's functionally the same as if you nested these yourself. But it still produces easier to read code without all that indentation.
Forwarding Notifications
Do you remember the forwarding of Exchange
's change notifications in the CurrencyListViewModel
in order to get the CurrencyList
to reload? It's time to clean that up with some additional Provider
types.
You can use a ProxyProvider to mediate the exchange of notifications between the two model objects: Exchange
to CurrencyListViewModel
. Think of a ProxyProvider as a transformer for providers that can take the updates from one or more providers and output with a new provider.
To do that, open lib\ui\view_models\currency_list_viewmodel.dart. Then, delete the body from the CurrencyListViewModel
constructor.
Next, add the following method at //TODO: add exchangeUpdated()
:
void exchangeUpdated() => notifyListeners();
This helper will forward the notifications to update the view.
Next, open lib\ui\views\currency_list.dart. You'll need to make a few adjustments to build()
so replace it with:
@override
Widget build(BuildContext context) {
// 1
return MultiProvider(
providers:
[
// 2
ChangeNotifierProvider.value(value: exchange),
// 3
ChangeNotifierProxyProvider<Exchange, CurrencyListViewModel>(
create: (context) => CurrencyListViewModel(
// 4
exchange: Provider.of<Exchange>(context, listen: false),
favorites: favorites,
wallet: wallet
),
// 5
update: (_, __, vm) => vm!..exchangeUpdated(),
),
],
// 6
child: Consumer<CurrencyListViewModel> (
builder: (_, model, __) => buildListView(model),
),
);
}
The updated method takes advantage of some concepts you saw in the last section and introduces some new ones as well:
- The
MultiProvider
is used here since there are two providers. - Using
ChangeNotifierProvider.value
allows you to make aChangeNotifierProvider
from an existingChangeNotifier
object. The exchange object's lifecycle is managed outside of this file, so it shouldn't be created by the provider. -
ChangeNotifierProxyProvider
is a specialized form ofProxyProvider
forChangeNotifiers
. This declares thatChangeNotifier
forCurrencyListViewModel
will be the proxy for anExchange
provider. - The
create
block is used to instantiate the new value for the provider.Provider.of<Exchange>(context)
grabs the value from theExchange
provider in the suppliedBuildContext
. This is the function-form of theConsumer
widget. Thelisten: false
is important inside acreate
block to prevent the widget tree from updating due to the state changes caused by the init. - The
update
block is called in response to change notifications from the proxied object, the exchange. This is where the updates are passed along from the change notifications. - This time, there is only a single
Consumer
. Thischild
widget is the same as it was before.
Rebuild and run, and the currency list should still reload automatically once the data loads!
The updated code still forwards the exchange updates to the view through the viewmodel. The advantage of using ProxyProvider
is that you don't have to add and remember to clean up listeners. The type definitions lay out the dependency.
Congratulations, you've completed this tutorial.
Where to Go From Here
There are a few areas to explore from this point. One next step is to implement a version of CurrencyService
that connects to a live API such as Open Exchange Rates. Specialized providers such as FutureProvider
and StreamProvider
are useful for listening to network events.
Provider is a relatively simple state management package that enables app architectures like MVVM (model-view-viewmodel) as used in this app. The Flutter documentation covers several other state management patterns such as Redux, BLoC and MobX.
Of course, to go into more depth on this topic check out the State Management Video course and The Flutter Apprentice.
If you have any questions or comments, please join the forum discussion below!