Flutter Intermediate Lesson 58 of 135 2 min read
Fish Redux in Flutter: What It Is and Should You Use It?
Understand Fish Redux, Alibaba's Redux-based Flutter architecture: State, Action, Reducer, Effect and View, and what to use instead for new apps.
On this page
Fish Redux is a Redux-based application architecture for Flutter, created by Alibaba for its Xianyu app. It splits every page into small parts (State, Action, Reducer, Effect and View) and connects them like Redux.
Important: Fish Redux has not been actively developed for several years and is not kept up to date with current Flutter releases. Do not start a new project with it. It is worth knowing because you may meet it in older code bases, and its ideas (separating effects from reducers) appear in other tools. For new apps, use Riverpod or Bloc.
The five parts of a page
| Part | Job |
|---|---|
| State | The data of the page. Must implement Cloneable (clone()). |
| Action | A message: “add”, “load”, “delete”. |
| Reducer | A pure function: old state + action → new state. |
| Effect | Side effects: API calls, navigation, timers. |
| View | A function that builds widgets from state and can dispatch actions. |
A counter page (legacy code)
This is how a Fish Redux counter looks. It is shown so you can read existing code.
// Not standalone: legacy Fish Redux code, split across several files.
// state.dart
class CounterState implements Cloneable<CounterState> {
int count = 0;
@override
CounterState clone() => CounterState()..count = count;
}
CounterState initState(Map<String, dynamic>? args) => CounterState();
// action.dart
enum CounterAction { add }
class CounterActionCreator {
static Action add() => const Action(CounterAction.add);
}
// reducer.dart
Reducer<CounterState> buildReducer() => asReducer({CounterAction.add: _add});
CounterState _add(CounterState state, Action action) =>
state.clone()..count = state.count + 1;
// view.dart
Widget buildView(CounterState state, Dispatch dispatch, ViewService viewService) {
return Scaffold(
body: Center(child: Text('${state.count}')),
floatingActionButton: FloatingActionButton(
onPressed: () => dispatch(CounterActionCreator.add()),
child: const Icon(Icons.add),
),
);
}
// page.dart
class CounterPage extends Page<CounterState, Map<String, dynamic>> {
CounterPage()
: super(initState: initState, reducer: buildReducer(), view: buildView);
}
What to use instead
| If you liked… | Use |
|---|---|
| The Redux one-way flow | Redux with flutter_redux |
| Events in, states out, effects separated | Bloc |
| Small, testable units with dependency injection | Riverpod |
Try it yourself
Take the counter above and rewrite it with a Cubit. Count how many files and classes you needed in each version.