Redux: Persist Your State

Zack
Async
Published in
4 min readOct 27, 2017

Part 1: Why?

1.1 Why Persist

When your app reloads, the javascript process has nothing in memory. You create your store from scratch, initialize state, and maybe set some basic state based on the url (if you are in a browser). In the case of the browser, your url is basically a serialization of state.

  1. Not all state is well represented by the url. e.g. user preferences are not appropriate to store in the url as a url is intended to be shareable.
  2. It is time consuming and expensive to refetch data every time the page loads. If everything is stored on disk, any given page can be refreshed in milliseconds rather than seconds.
  3. There is no url in native contexts. This means the patterns you are used to on the web do not map well to iOS / Android / Electron apps.
  4. Offline First. Your users do not have stable internet connections. Persistence is the first step of offline support.

1.2 Why Redux Persist

There is no two ways about it, persistence is hard. We are talking about an ever changing blob of state that travels through time at discrete intervals. And when one of these state blobs shows up, the application needs to process it. But the blob could be days, weeks or years old!

Redux Persist provides a consistent, performant, and structured way to persist state.

If you still require more convincing, read Jani Eväkallio’s piece on offline first applications.

Part 2: Architecture

2.1 The Component Parts

The “persistence layer” is actually two stateful reactive objects, plus a higher order reducer.

Persistor
The persistor can be thought of as the persistence lifecycle orchestrator. This is the object returned by persistStore, it kicks off the persistence process via a PERSIST action. It also creates register and rehydrate methods which will be used to register each persistoid, and dispatch the actual rehydrate action respectively.

Persistoid
The persistoid is the actual state sink. It is quite simple, just a function which takes state as an argument and handles quickly and efficiently writing that state to disk.

Persisted Reducer
The persisted reducer is a small wrapper around any other reducer that can be best explained by its lifecycle:

1. picks up the PERSIST action
2. creates the persistoid
3. it begins reading state from disk
4. fires the REHYDRATE action
5. whenever state changes, notify the persistoid
6. additionally it handles the PURGE action for clearing stored state.

2.2 Whats new in Redux Persist v5

  • code splitting reducers
  • better integration story for libs (e.g. redux-offline)
  • ability to colocate persistence rules with the reducer it pertains to
  • first class migration support
  • enable PersistGate react component which blocks rendering until persistence is complete (and enables similar patterns for integration)
  • nest persistence configuration

Redux? Thats not cool anymore

Actually it is pretty great, exactly for this reason. It provides a consistent and simple interface to work with state. In fact redux-persist uses a redux store internally to power the persistor! Thats means a consistent story around extensibility, and the ability to use redux-devtools to debug any tricky issues internal to the persistence layer.

Ergonomic Redux

Vanilla Redux requires a ton of ceremony to use. Between actions, reducers, selectors, connectors, the simplest feature might touch 4+ files. Our hope is that redux-persist fits into a new set of libraries that allow for a more ergonomic usage of redux.

Without sacrificing simplicity, nor type safety, it should be possible to define your state declaratively and receive back the methods necessary to build your app.

Redux Persist v5 solves one small part of this problem: declarative persistence.

Whats Next

npm i -S redux-persist@next

Please help test v5 here. Note the api has changed so please check the readme. Open an issue if you have questions or concerns. PRs are welcome.

🎈

Huge Thanks to

214k dl/mo, yet only ~%5 of all redux downloads!

--

--