top of page

[Flutter/dart] Save the state of Redux Store / How to use redux_persist


In many cases, you want to retain the data set by the user even after the application is closed. If you are using redux for state management, you can easily persist your data by using a library called redux_persist.


※I will assume that flutter_redux is already installed.


First, add the following to pubsec.yaml.

    redux_persist: ^0.8.4

Import the library at the beginning of main.dart.

(I think that it is basically used in main.dart, but if it is different, please read as appropriate)

import 'package:redux_persist/redux_persist.dart';


The managed state is AppState. We will add the necessary processing to AppState.

Initialization processing is required when there is no data yet.

class AppState{

  String item;
  int number;
  AppState({@required this.items,});
  //Initialization processing
  AppState.InitState() {

When saving the state, convert the data to json format. Add conversion to json and read processing from json.

//convert to json
Map toJson()=>{
  'item': item,
  'number': number,

//read from json
static AppState fromJson(dynamic json){
  AppState state=AppState(
    item: json['item'],
  return state;

Save method

Here is the main issue. Add the following processing before runApp () of main.

void main() async{

//get the path of local directory
  String _storage_path=await getLocalDir();
  final persistor = Persistor<AppState>(
    storage: FileStorage(File("${_storage_path}/state.json")),
    serializer: JsonSerializer<AppState>(AppState.fromJson),
  );  //※1 create persistor

  AppState initialState;
    initialState=await persistor.load();
  }  //※2 ead data from persistor

  final Store<AppState> store=Store<AppState>(
    appStateReducer,  //※self-made reducer
    initialState: initialState?? AppState.InitState(),
    middleware: [AppStateMiddleWare, persistor.createMiddleware()]
  ); //※3 Initialize store
  runApp(MyApp(store: store,));

First, create a persistor instance. (* 1)

For storage:, specify the data storage destination. Here, saving to a local file is used, but it seems that it can also be saved to the web etc.

The following method is used to get the local directory.

static Future<String> getLocalDir() async {
  final directory = await getApplicationDocumentsDirectory();
  return directory.path;

For serializer :, specify the serializer of the data. Here, JsonSerializer is used and the fromJson method created earlier is specified in the decoder.

Next, read the data from the persistor (* 2). If the data has not been saved yet, fromJson will return null, so exception handling will be included. (I added the initialization process later, but you may add it with the catch statement here)

Finally, initialize the Store (* 3).

Put the state read from the persistor in initState :, and initialize the state if null is returned.

The process of saving data is done by middleware provided by redux_persistor. Specify the middleware generated by persistor.createMiddleware () in middleware:.

About middleware

・When is the data saved?

The source code of createMiddleware() is as follows.

Middleware<T> createMiddleware() {
  Timer _saveTimer;

  return (Store<T> store, dynamic action, NextDispatcher next) {

    if (shouldSave != null && shouldSave(store, action) != true) {

    // Save
    try {
      if (throttleDuration != null) {
        // Only create a new timer if the last one hasn't been run.
        if (_saveTimer?.isActive != true) {
          _saveTimer = Timer(throttleDuration, () => save(store.state));
      } else {
    } catch (_) {}

Since there is a save () process after next (action), the data is saved after the action (data change, etc.) (obviously).

・Want to use my own middleware

Besides saving data, there are other things you want middleware to do. If you also want to use your own middleware that describes such processing, you can put them together in a List and pass them to middleware:.

The middleware processing is executed in order from the beginning of the List, and the next middleware is executed by next (). The next of the last middleware is action. If the order of processing is important, pay attention to the order of List and the position of next.


Actually, at first I saved the data in shared_preference without knowing redux_persistor, but with redux_persist it is quite easy to save the data. It's important to find out ...

Recent Posts

See All

[Flutter/Dart] Format string with TextField

What want to do I want to create an input form using TextField. For example, if the input content is a monetary amount, I would like to display it in 3-digit delimiters with a ¥ prefix. Rather than ha


Let's do our best with our partner:​ ChatReminder


It is an application that achieves goals in a chat format with partners.


Let's do our best with our partner:​ ChatReminder


It is an application that achieves goals in a chat format with partners.


Theme diary: Decide the theme and record for each genre

It is a diary application that allows you to post and record with themes and sub-themes for each genre.

bottom of page