0 purchases
provider for redux
provider_for_redux #
With Provider you can inject your state, but it's
your job to figure out how to update that state, structure the solution etc. In other words,
Provider is a great alternative to InheritedWidget, and lets you do dependency injection, but you
still need to do your own state management.
What people mean by “Provider as state management” is usually using Provider to do scoped model. But
as a matter of fact, this is not the only possible architecture using Provider. You can use it with
Bloc, Mobx, Redux and other.
This package lets you use it with AsyncRedux, the
non-boilerplate version of Redux.
How to use it #
Please, read the async_redux documentation first,
if you haven't already.
You should have learned that to use AsyncRedux the traditional way, you provide the Redux store to
your app by wrapping it with a StoreProvider, and then using the so called "connector" widgets,
like the MyHomePageConnector below:
@override
Widget build(BuildContext context) =>
StoreProvider<AppState>(
store: store,
child: MaterialApp(
home: MyHomePageConnector(),
));
copied to clipboard
Now, if you want to use AsyncRedux with Provider, simply remove the StoreProvider and
use AsyncReduxProvider instead. Also, you won't need the connector widgets anymore, since you will
use Provider instead.
For example:
@override
Widget build(BuildContext context) =>
AsyncReduxProvider<AppState>.value( // Instead of StoreProvider.
value: store,
child: MaterialApp(
home: MyHomePage(), // Instead of MyHomePageConnector.
));
copied to clipboard
The AsyncReduxProvider widget above will expose the store, the state, and the dispatch method to
its descendants:
The Redux store, of type Store. Get it like this: Provider.of<Store<AppState>>(context).
The store's state, of type AppState. Get it like this: Provider.of<AppState>(context).
The dispatch method, of type Dispatch. Get it like this: Provider.of<Dispatch>(context).
This is a complete example:
class MyHomePage extends StatelessWidget {
MyHomePage({Key key}) : super(key: key);
int counter(context) =>
Provider
.of<AppState>(context)
.counter;
String description(context) =>
Provider
.of<AppState>(context)
.description;
VoidCallback onIncrement(context) =>
() => Provider.of<Dispatch>(context, listen: false)(IncrementAndGetDescriptionAction());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Increment Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("You've pushed the button:"),
Text('${counter(context)}', style: TextStyle(fontSize: 30)),
Text('${description(context)}', style: TextStyle(fontSize: 15)),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: onIncrement(context),
child: Icon(Icons.add),
),
);
}
}
copied to clipboard
Try running
the
Provider.of example.
Consumer #
You can use Provider's
Consumer
class to read from the store.
For
example:
return Consumer<Store<AppState>>(
builder: (context, store, child) =>
...
Text('${store.state.counter}'),
...
onPressed: () => store.dispatch(IncrementAction()),
),
copied to clipboard
But it's easier if you use ReduxConsumer, which already gives you the store, the state, and the
dispatch method:
return ReduxConsumer<AppState>(
builder: (context, store, state, dispatch, child) => ...
copied to clipboard
This is a complete example:
class MyHomePage extends StatelessWidget {
MyHomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ReduxConsumer<AppState>(
builder: (context, store, state, dispatch, child) => Scaffold(
appBar: AppBar(title: Text('Increment Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("You've pushed the button:"),
Text('${state.counter}', style: TextStyle(fontSize: 30)),
Text('${state.description}', style: TextStyle(fontSize: 15)),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => dispatch(IncrementAndGetDescriptionAction()),
child: Icon(Icons.add),
),
),
);
}
}
copied to clipboard
Try running
the
ReduxConsumer example.
Selector #
You can use Provider's
Selector
class to read from the store, while preventing unnecessary widget rebuilds.
For
example:
return Selector<Store<AppState>, Tuple2<int, Dispatch>>(
selector: (context, store) =>
Tuple2(store.state.counter, store.dispatch),
builder: (context, model, child) =>
...
Text('${model.item1}'),
...
onPressed: () => model.item3(IncrementAction()),
),
copied to clipboard
Your selector parameter must return a "model"
which you can use to build your widget in the builder parameter. In the above example the model is
a Tuple2 instance, but you can return any immutable object that correctly implements equals and
hashcode. The widget will rebuild whenever the model changes.
But it's easier if you use ReduxSelector, which already gives you the store, the state, and the
dispatch method:
return ReduxSelector<AppState, Tuple2<int, String>>(
selector: (context, state) => Tuple2(state.counter, store.dispatch),
builder: (ctx, store, state, dispatch, model, child) =>
...
Text('${state.counter}'),
...
onPressed: () => store.dispatch(IncrementAction()
),
),
copied to clipboard
Try running
the
ReduxSelector with model example.
However, ReduxSelector also lets you return a List as the model. In case you do that, it will
rebuild the widget whenever any of the items in the list changes:
return ReduxSelector<AppState, dynamic>(
selector: (context, state) => [...],
builder: (context, store, state, dispatch, model, child) => ...
copied to clipboard
Using ReduxSelector with a list is the easiest way of all, since you just need to list all of
the state parts that should trigger a rebuild.
Note: The builder gives you both the state and the model, and you can choose one of them
to build your widget from. While using state is probably easier for you, it's also easier to
accidentally use something you forget to add to the model, and then wonder why the Widget doesn't
rebuild. So you have two options:
Use only the model and have the compiler make sure there's no state you're using from outside
of the model.
Use state directly, and have yourself the responsibility to make you've listed everything you'
re using in the model.
This is a complete example:
Widget build(BuildContext context) {
return ReduxSelector<AppState, dynamic>(
selector: (context, state) => [
state.counter,
state.description
],
builder: (context, store, state, dispatch, model, child) =>
Scaffold(
appBar: AppBar(title: Text('Increment Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("You've pushed the button:"),
Text('${state.counter}', style: TextStyle(fontSize: 30)),
Text('${state.description}', style: TextStyle(fontSize: 15)),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => dispatch(IncrementAndGetDescriptionAction()),
child: Icon(Icons.add),
)));
}
copied to clipboard
Try running
the
ReduxSelector with list example.
Migrating #
When you use AsyncReduxProvider you will notice that both Provider and
AsyncRedux's StoreConnector
will work simultaneously. You can mix and match both of them, as desired, or slowly migrate between
them.
Special thanks for Remi Rousselet, main author of
Provider, for helping me with ideas and making suggestions.
The Flutter packages I've authored:
async_redux
fast_immutable_collections
provider_for_redux
i18n_extension
align_positioned
network_to_file_image
image_pixels
matrix4_transform
back_button_interceptor
indexed_list_view
animated_size_and_fade
assorted_layout_widgets
weak_map
themed
bdd_framework
My Medium Articles:
Async Redux: Flutter’s non-boilerplate version of Redux (
versions:
Português)
i18n_extension (
versions:
Português)
Flutter: The Advanced Layout Rule Even Beginners Must Know (
versions: русский)
The New Way to create Themes in your Flutter App
My article in the official Flutter documentation:
Understanding constraints
---Marcelo Glasberg:
https://github.com/marcglasberg
https://twitter.com/glasbergmarcelo
https://stackoverflow.com/users/3411681/marcg
https://medium.com/@marcglasberg
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.