Flutter Tutorial

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

PartJob
StateThe data of the page. Must implement Cloneable (clone()).
ActionA message: “add”, “load”, “delete”.
ReducerA pure function: old state + action → new state.
EffectSide effects: API calls, navigation, timers.
ViewA 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 flowRedux with flutter_redux
Events in, states out, effects separatedBloc
Small, testable units with dependency injectionRiverpod

Try it yourself

Take the counter above and rewrite it with a Cubit. Count how many files and classes you needed in each version.

Practise in the playground Updated