Tl;dr: Go visit this package and see the example section.
What is State Management?
For those of you who are new to flutter: There should be no app which only display a single static screen, right? An app like this is no difference than an image. Every app should have certain parts of UIs which depends on some data, that data is called state. The process of structuring the state, and making the UI refreshes upon the change of the state is hence named state management.
State Management with ChangeNotifier
In Flutter there are many ways to do state management. One of the ways is by using ChangeNotifier
. Comparing to the setState
method, using ChangeNotifier
lets you share the state among different widgets of your app, without having to worry about passing around the properties or “on change callbacks” by widget parameters.
Let’s start by creating an instance of the model:
class CounterModel extends ChangeNotifier {
int _count = 0;
void increment() {
_count++;
notifyListeners();
}
int get count => _count;
}
Simple enough. It has an integer count
value, and a method to increase the value by 1.
Then we create an instance of the model somewhere:
final CounterModel counterModel = CounterModel();
Then the UI. Here comes the real trick:
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My Home Page'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
ChangeNotifierBuilder(
// supply the instance of `ChangeNotifier` model,
// whether you get it from the build context or anywhere
notifier: counterModel,
// this builder function will be executed,
// once the `ChangeNotifier` model is updated
builder: (BuildContext context, CounterModel? counter, _) {
return Text(
'${counter?.count ?? ''}',
style: Theme.of(context).textTheme.headline4,
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _counterModel.increment,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Wrap the portion of your widget, which depends on the value of the model, in a ChangeNotifierBuilder
. The UI will be updated once the notifyListener
s method inside the model is invoked. The smaller the portion is, the faster the rebuild.
ChangeNotifierBuilder
Wait. You said there is no such thing as ChangeNotifierBuilder
?
You’re right! This is a package created by me. Or you can use AnimatedBuilder
instead, they are pretty much the same thing.
But I created the package for 3 reasons:
For the purpose of state management,
ChangeNotifierBuilder
is a more reasonable and readable name thanAnimatedBuilder
, for a builder widget.Sometimes our model is not yet ready (i.e. equals
null
). In this case if you useAnimatedBuilder
, it throws "animation cannot be null" exception. However, if you useChangeNotifierBuilder
, the runtime value ofnotifier
can benull
.The
builder
method provides you theT notifier
object as a parameter, which is a bit more user-friendly.You can’t listen to multiple
ChangeNotifier
s withAnimatedBuilder
, so I createdMultiChangeNotifierBuilder
for this purpose.
Optimizing Performance
There are 3 techniques to boost performance when using ChangeNotifierBuilder
and MultiChangeNotifierBuilder
:
Never wrap the builder around the root of your widget tree. Since we want to minimize the number of widgets to rebuild on every update, try wrapping the builder around the widgets which depend on the model only (the further away from the root the better, i.e. the leaves).
If the
builder
callback’s return value contains a subtree that does not depend on the model, you may pass it as thechild
parameter, instead of rebuilding it every time.Don’t supply models which are not depended by the widget tree. Because unnecessary rebuilds will be triggered when those models update.
Putting it all together
The final piece of the puzzle is, how do you pass the same instance of the model around your app?
You can do it by creating a singleton model, or using the fantastic community packages like provider or get_it.
Top comments (0)