flutter_store
is a simple way for state management outside of Rendering Tree inspired by Flutter it self.
Why yet another state management? There are Redux
, MobX
, BLoC
and other solution to manage state outside of the widgets tree. All those packages are great but for many scenarios quite opinionated:
Redux
uses a single store with actions and reducers etc.MobX
while very clean and simple with react introduce quite a bit of boilerplate or require code generation.BLoc
rely on streams and generally is quite opinionated about how we should design the business logic of the app.
If we think about it, Flutter already providing the state management features like StatefulWidget
to store the states and InheritedWIdget
to deliver our data to target widgets. But using those to also require quite a bit of the boilerplate.
The flutter_store
works just like a StatefulWidget
but existing outside of the widgets tree. It uses the same setState
method (to be consistent with Flutter itself) to notify widgets that its state changed and Provider
to pass our store throw the widgets tree. For example:
class _Counter extends Store {
int value = 0;
void increment() => setState(() {
value += 1;
});
}
For those who develop the app with Flutter, this code snippet should look very familiar. It works exactly like StatefulWidget
and all widgets which rely on it, will be notified and updated.
- To create the our one store, we just need to extend the
Store
provided byflutter_store
package.
class _Counter extends Store {
int _value = 0;
get value => _value;
void increment() => setState(() {
_value += 1;
});
}
We do not want to update the value outside of the setState
so we will make it private and access it via getter.
- Now we will gonna pass our store down the widgets tree with the
Provider
widget. That way we will be able to access our store anywhere in the tree.
final _counter = _Counter();
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provider(
store: _counter,
child: MyChildWIdget()
);
}
}
- Now, we can access our store anywhere in the widgets tree since the
Provider
is widget is just a wrapper around theInheritedWidget
.
class MyChildWIdget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = Provider.of<_Counter>(context);
return Text('${counter.value}');
}
}
The flutter_store
is not opinionated, so you can store any value inside the store. For example, you can turn your value to the stream and use store and provider to pass that stream to the target component (BLoc).
flutter_store
also has Cache
mixin inspired by MobX's computed
decorator, but it does not rely on code generation.
class _Counter extends Store with Cache {
int _value = 0;
get value => _value;
get valueStr => _valueStr(_valueStr);
String _valueStr() => value.toString();
void increment() => setState(() {
_value += 1;
});
}
The reason why this mixin is an experimental
is:
- The
Cache
mixing, using is usingLinkedHashMap
to store cached results, thus it does not make much sense to use the cache for simple methods like the one above from performance perspective. - The cache is using the method address as the cache key, thus, you cannot use the
anonymous functions
as the cache parameter, because in that case, the new function will be created on every cache call, which will lead to memory leaks. (should we also have named cached?..)