Dispatching actions
As discussed, the only way to change the store state is by dispatching actions.
The two places where you usually dispatch actions from are:
- From inside a widget, using the dispatch extension methods on the widget
context
(more on that later). - From inside actions dispatching other actions. All actions have access to the dispatch methods.
There are five "dispatch methods" that you can choose from. Let's study them in detail.
1. Dispatch
The most common one is simply dispatch(MyAction())
. This will dispatch the action and return
immediately. If the action is sync, the state will be updated before the method returns.
If the action is async, this will start an async process and the state will be updated eventually
when the action completes.
2. DispatchAndWait
Another dispatch method is dispatchAndWait(MyAction())
. This is similar to dispatch()
, but it
will return a Future
that completes when the action is done. This is useful if you want to wait
for the action to complete and change the state before continuing, no matter if the action is sync
or async:
await dispatchAndWait(MyAction());
print('Action completed');
3. DispatchAll
Another dispatch method is dispatchAll([])
, which dispatches all given actions in parallel,
applying their reducer, and possibly changing the store state. For example:
dispatchAll([
BuyAction('IBM'),
SellAction('TSLA')
]);
Note this is very similar to:
dispatch(BuyAction('IBM'));
dispatch(SellAction('TSLA'));
Moreover, the dispatchAll
method returns the list of dispatched actions,
so that you can instantiate them inline, but still get a list of them:
// Get a list of actions do to something with them later
var actions = dispatchAll([MyAction1(), MyAction2()]);
4. DispatchAndWaitAll
Another dispatch method is dispatchAndWaitAll
, which dispatches all given actions in parallel,
applying their reducers, and possibly changing the store state. The actions may be sync or async.
It returns a Future
that resolves when all actions finish, which means you can await it:
await store.dispatchAndWaitAll(
[
BuyAction('IBM'),
SellAction('TSLA')
]
);
Note: While the state change from the actions' reducers will have been applied when the Future resolves, other independent processes that the action may have started may still be in progress.
It also returns the list of dispatched actions, if you need it:
var actions = await store.dispatchAndWaitAll([MyAction1(), MyAction2()]);
This is very similar to:
var action1 = MyAction1();
var action2 = MyAction2();
dispatch(action1);
dispatch(action2);
await store.waitAllActions([action1, action2], completeImmediately = true);
var actions = [action1, action2];
Note we haven't discussed waitAllActions
yet, but it's a method that waits for a list of actions
to complete. Just ignore it for now.
5. DispatchSync
The last dispatch method is dispathSync(MyAction())
. This is similar to dispatch()
, but it
will throw a StoreException
if the action is async.
This is useful if you want to ensure that the action is sync and that the state is updated before
continuing. In practice this is rarely needed, because you can always use dispatchAndWait()
irrespective of the action being sync or async.
Also, as you'll see in practice, knowing if the action is sync or async when you dispatch it is not very useful anyway, because things just work without you having to pay attention to this detail.
Dispatching from widgets
It's easy to access all dispatch methods from inside your widgets, as Async Redux defines
an extension on context
.
Suppose a button in your widget needs to dispatch an action to increment a counter. This is how you can do it:
class MyWidget extends StatelessWidget {
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => context.dispatch(IncrementAction()),
child: Text('Increment'),
);
}
You have access to all dispatch methods:
context.dispatch(MyAction());
context.dispatchAll([MyAction1(), MyAction2()]);
await context.dispatchAndWait(MyAction());
await context.dispatchAndWaitAll([MyAction1(), MyAction2()]);
context.dispatchSync(MyAction());
Action status
Some of the above dispatch methods return an ActionStatus
(or a future of it),
which contains some useful information about the action. This is an advanced feature that you can
ignore for now.
The notify
parameter
All dispatch methods have an optional notify
parameter. If you pass false
, widgets will not
necessarily rebuild because of the dispatched action, even if it changes the state.
The default is true
as almost always you do want the widgets to rebuild, in which case you can
safely ignore this parameter.
Next, let's see how to deal with actions that fail and throw errors, and let's learn about
a special kind of error called a UserException
.