redux_machine 0.0.1 redux_machine: ^0.0.1 copied to clipboard
State machine with Redux flow
redux_machine #
Writing state machines is hard, but not with this library.
This is a small library which allows running state machines using Redux flow.
Usage #
Redux requires three things: state, actions and reducers.
We start by defining our state object. Here is an example of a coin-operated turnstile (from Wikipedia):
class TurnstileState {
final bool isLocked;
final int coinsCollected;
final int visitorsPassed;
TurnstileState(this.isLocked, this.coinsCollected, this.visitorsPassed);
/// Convenience method to use in reducers.
TurnstileState copyWith({
bool isLocked,
int coinsCollected,
int visitorsPassed,
}) {
return new TurnstileState(
isLocked ?? this.isLocked,
coinsCollected ?? this.coinsCollected,
visitorsPassed ?? this.visitorsPassed,
);
}
}
Next, actions:
class Actions {
/// Put coin to unlock turnstile
static const ActionBuilder<Null> putCoin =
const ActionBuilder<Null>('putCoin');
/// Push turnstile to pass through
static const ActionBuilder<Null> push = const ActionBuilder<Null>('push');
}
And reducers:
TurnstileState putCoinReducer(
TurnstileState state, Action<Null> action, MachineController controller) {
int coinsCollected = state.coinsCollected + 1;
print('Coins collected: $coinsCollected');
return state.copyWith(isLocked: false, coinsCollected: coinsCollected);
}
TurnstileState pushReducer(
TurnstileState state, Action<Null> action, MachineController controller) {
int visitorsPassed = state.visitorsPassed;
if (!state.isLocked) {
visitorsPassed++;
print('Visitors passed: ${visitorsPassed}');
}
return state.copyWith(isLocked: true, visitorsPassed: visitorsPassed);
}
Now get it all together:
void main() {
// Create our machine and register reducers:
ReduxMachine<TurnstileState> machine = new ReduxMachine<TurnstileState>();
machine
..addReducer(Actions.putCoin, putCoinReducer)
..addReducer(Actions.push, pushReducer);
// Start the machine with initial state.
machine.start(new TurnstileState(true, 0, 0));
// Try triggering some actions
machine.trigger(Actions.push());
machine.trigger(Actions.putCoin());
// .. etc.
// Make sure to shutdown the machine in the end:
machine.shutdown();
}
Chaining actions #
Sometimes it is useful to trigger another action from inside current reducer.
It is possible via MachineController
argument passed to each reducer function.
Simply call controller.become(yourNextAction(payload));
before returning
updated state, e.g.:
State exampleReducer(
State state, Action<Null> action, MachineController controller) {
// do work here
// ...
// State machine will call reducer for `otherAction` with the state object
// returned from this reducer.
controller.become(Actions.otherAction());
return state.copyWith(exampleField: 'value');
}
Features and bugs #
Please file feature requests and bugs at the issue tracker.