redux_persist 0.7.0

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 92

redux_persist pub package

Persist Redux state across app restarts in Flutter, Web, or custom storage engines.

Features:

  • Save and load from multiple engine (Flutter, Web, custom)
  • Fully type safe
  • Transform state and raw on load/save
  • Flutter integration (PersistorGate)
  • Easy to use, integrate into your codebase in a few minutes!

Storage Engines:

Usage

See Flutter example for a full overview.

The library creates a middleware that saves on every action. It also loads on initial load and sets a LoadedAction to your store.

State Setup

You will need to use a state class, with a required toJson method, as such:

class AppState {
  final int counter;

  AppState({this.counter = 0});

  AppState copyWith({int counter}) =>
      AppState(counter: counter ?? this.counter);

  // !!!
  static AppState fromJson(dynamic json) => AppState(counter: json["counter"]);

  // !!!
  dynamic toJson() => {'counter': counter};
}

(the copyWith method is optional, but a great helper. The fromJson is required as decoder, but can be renamed)

Persistor

Next, create your persistor, storage engine, and store, then load the last state in. This will usually be in your main or in your root widget:

// Create Persistor
final persistor = Persistor<AppState>(
  storage: FlutterStorage("my-app"), // Or use other engines
  decoder: AppState.fromJson,
);

// Create Store with Persistor middleware
final store = Store<AppState>(
  reducer,
  initialState: AppState(),
  middleware: [persistor.createMiddleware()],
);

// Load state to store
persistor.start(store);

(the key param is used as a key of the save file name. The decoder param takes in a dynamic type and outputs an instance of your state class, see the above example)

Load

In your reducer, you must add a handler for the PersistLoadedAction action (with the generic type), like so:

class IncrementCounterAction {}

AppState reducer(state, action) {
  // !!!
  if (action is PersistLoadedAction<AppState>) {
    return action.state ?? state; // Use existing state if null
  }else if (action is IncrementCounterAction) {
    return state.copyWith(counter: state.counter + 1);
  }

  return state;
}

Optional Actions

The persistor dispatches a few other actions based on it's lifecycle:

  • PersistLoadAction is dispatched when the store is being loaded
  • PersistErrorAction is dispatched when an error occurs on loading/saving

Storage Engines

You can use different storage engines for different application types:

  • Flutter

  • Web

  • FileStorage:

    final persistor = Persistor<AppState>(
      // ...
      storage: FileStorage("path/to/state.json"),
    );
    
  • Build your own custom storage engine:

    To create a custom engine, you will need to implement the following interface to save/load a string to disk:

    abstract class StorageEngine {
      external Future<void> save(String json);
    
      external Future<String> load();
    }
    

Whitelist/Blacklist

To only save parts of your state, simply omit the fields that you wish to not save from your toJson and decoder (usually fromJson) methods.

For instance, if we have a state with counter and name, but we don't want counter to be saved, you would do:

class AppState {
  final int counter;
  final String name;

  AppState({this.counter = 0, this.name});

  // ...

  static AppState fromJson(dynamic json) =>
      AppState(name: json["name"]); // Don't load counter, will use default of 0


  Map toJson() => {'name': name}; // Don't save counter
}

Migrations

As your state grows, you will need new state versions. You can version you state and apply migrations between state versions.

Versions are integers, starting at 0. You may use any integer as long as it is higher than the last version number.

Migrations are pure functions taking in a dynamic state, and returning a transformed state (do not modify the original state passed).

final persistor = Persistor<State>(
  // ...
  version: 1,
  migrations: {
    // Renamed fields from "oldCounter" to "counter"
    0: (dynamic state) => {"counter": state["oldCounter"]},
    // "counter" is now a string
    1: (dynamic state) => {"counter": state["counter"].toString()                                                                       }
  },
);

Transforms

All transformers are ran in order, from first to last.

Make sure all transformation are pure. Do not modify the original state passed.

State

State transformations transform your state before it's written to disk (on save) or loaded from disk (on load).

final persistor = Persistor<AppState>(
  // ...
  transforms: Transforms(
    onSave: [
      // Set counter to 3 when writing to disk
      (state) => state.copyWith(counter: 3),
    ],
    onLoad: [
      // Set counter to 0 when loading from disk
      (state) => state.copyWith(counter: 0),
    ],
  ),
);

Raw

Raw transformation are applied to the raw text (JSON) before it's written to disk (on save) or loaded from disk (on load).

final persistor = Persistor<AppState>(
  // ...
  rawTransforms: RawTransforms(
    onSave: [
      // Encrypt raw json
      (json) => encrypt(json),
    ],
    onLoad: [
      // Decrypt raw json
      (json) => decrypt(json),
    ],
  )
);

Debug

Persistor has a debug option, which will eventually log more debug information.

Use it like so:

final persistor = Persistor<AppState>(
  // ...
  debug: true
);

Errors

Middleware errors (save/load) are dispatched as PersistErrorAction and broadcasted to persistor.errorStream(alongside debug).

Features and bugs

Please file feature requests and bugs at the issue tracker.

0.7.0-rc.2 - 2018-04-09

  • Fix middleware typing.

0.7.0-rc.1 - 2018-03-31

  • Breaking: Dart 2.
  • Breaking: Upgraded redux to v3.0.0.
  • Breaking: Changed loading flow:
    • persistor.start has been deprecated (will be removed in next major version). Use persistor.load
    • Loading dispatched PersistLoadAction, then PersistLoadedAction once completed.
  • Breaking: Changed action names:
    • LoadAction: PersistLoadingAction
    • LoadedAction: PersistLoadedAction
    • PersistorErrorAction: PersistErrorAction
  • Added saving actions (PersistSavingAction and PersistSavedAction)
  • Added MemoryStorage.
  • Added loadFromStorage and saveToStorage for more manual control.
  • Refactor, new tests.

0.6.0 - 2018-03-18

  • Breaking: Change saved state format. This will break your saved state, will only happen once.
  • Added migrations and version key.
  • Fix JSON deprecation warning.
  • Added tests.
  • Added exceptions.
  • Added FileStorage.

0.5.2 - 2018-03-14

  • Fix library export.

0.5.1 - 2018-03-13

  • Made persistor.start return a Future.
  • Add type to persistor.loadStream.

0.5.0 - 2018-03-12

  • Breaking: Change persistor.load(store) to persistor.start(store) for initial loading.
  • Breaking: Change LoadAction<T> to LoadedAction<T>.
  • Add LoadAction (action dispatch to start loading).
  • Add PersistorErrorAction (action dispatched on save/load error).
  • Add debug persistor option, doesn't do anything yet.

0.4.0 - 2018-03-10

  • Breaking: Decouple Flutter and Web into different packages.

0.3.0 - 2018-03-10

  • Add state and raw transformers.
  • Added better error handling (persistor.errorStream)

0.2.0 - 2018-03-10

  • Move Flutter-specific code to separate, unexported file. It is likely this will become it's own package.
  • Add SaveLocation for Flutter storage engine.
  • Add SharedPreference sub-engine for Flutter storage engine (make default).
  • Fix PersistorGatepassing variables to state and initialization.
  • Add more docs.

0.1.0 - 2018-03-09

  • Create generic StorageEngine.
  • Create FlutterStorage.

0.0.3 - 2018-03-09

  • Added documentation.

0.0.2 - 2018-03-09

  • Added PersistorGate.

0.0.1 - 2018-03-09

  • Initial release.

example/redux_persist_example.dart

import 'package:redux/redux.dart';
import 'package:redux_persist/redux_persist.dart';

void main() async {
  final persistor = Persistor<State>(
    storage: FileStorage("state.json"),
    decoder: State.fromJson,
  );

  final store = Store<State>(
    reducer,
    initialState: State(),
    middleware: [persistor.createMiddleware()],
  );

  // Load initial state
  await persistor.load(store);

  // ...
}

class State {
  final int counter;

  State({this.counter = 0});

  State copyWith({int counter}) => State(counter: counter ?? this.counter);

  static State fromJson(dynamic json) => State(counter: json["counter"] as int);

  dynamic toJson() => {'counter': counter};
}

class IncrementCounterAction {}

State reducer(State state, Object action) {
  if (action is PersistLoadedAction<State>) {
    // Load to state
    return action.state ?? state;
  } else if (action is IncrementCounterAction) {
    // Increment
    return state.copyWith(counter: state.counter + 1);
  }

  return state;
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  redux_persist: ^0.7.0

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter packages get

Alternatively, your editor might support pub get or flutter packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:redux_persist/redux_persist.dart';
  
Version Uploaded Documentation Archive
0.7.0 Aug 10, 2018 Go to the documentation of redux_persist 0.7.0 Download redux_persist 0.7.0 archive
0.6.0 Mar 19, 2018 Go to the documentation of redux_persist 0.6.0 Download redux_persist 0.6.0 archive
0.5.2 Mar 14, 2018 Go to the documentation of redux_persist 0.5.2 Download redux_persist 0.5.2 archive
0.5.1 Mar 13, 2018 Go to the documentation of redux_persist 0.5.1 Download redux_persist 0.5.1 archive
0.5.0 Mar 12, 2018 Go to the documentation of redux_persist 0.5.0 Download redux_persist 0.5.0 archive
0.4.0 Mar 10, 2018 Go to the documentation of redux_persist 0.4.0 Download redux_persist 0.4.0 archive
0.3.0 Mar 10, 2018 Go to the documentation of redux_persist 0.3.0 Download redux_persist 0.3.0 archive
0.2.0 Mar 10, 2018 Go to the documentation of redux_persist 0.2.0 Download redux_persist 0.2.0 archive
0.1.0 Mar 9, 2018 Go to the documentation of redux_persist 0.1.0 Download redux_persist 0.1.0 archive
0.0.3 Mar 9, 2018 Go to the documentation of redux_persist 0.0.3 Download redux_persist 0.0.3 archive

All 14 versions...

Popularity:
Describes how popular the package is relative to other packages. [more]
92
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
80
Overall:
Weighted score of the above. [more]
92
Learn more about scoring.

We analyzed this package on Sep 18, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.0.0
  • pana: 0.12.3

Platforms

Detected platforms: Flutter, other

Primary library: package:redux_persist/redux_persist.dart with components: io.

Suggestions

The description is too short.

Add more detail about the package, what it does and what is its target use case. Try to write at least 60 characters.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev <3.0.0
redux ^3.0.0 3.0.0
Dev dependencies
test ^0.12.33