sajad torkamani

Install redux-persist

npm i redux-persist

Setup and configure the persistor

// configureStore.js
import { createStore } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' // defaults to localStorage for web
import rootReducer from './reducers'
const persistConfig = {
  key: 'root',
  storage,
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
export default () => {
  let store = createStore(persistedReducer)
  let persistor = persistStore(store)
  return { store, persistor }
}

Wrap your root component with PersistGate

This will delay the rendering of your app’s UI until your persisted state has been retrieved and used to initialize your Redux store:

import { PersistGate } from 'redux-persist/integration/react'
// ... normal setup, create store and persistor, import components etc.
const App = () => {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <RootComponent />
      </PersistGate>
    </Provider>
  );
};

Configure how incoming state is merged with initial state

redux-persist gives you three options out of the box to control how the persisted / rehydrated state is merged with the initial state defined in your reducers.

autoMergeLevel1 (default)

The persisted state will be auto merged with the reducer’s initial state at one level deep. The reducer’s initial state will take precedence.

  • Persisted state{ foo: persistedFoo, bar: persistedBar }
  • Reducer initial state{ foo: reducerInitialFoo }
  • Reconciled state{ foo: reducerInitialFoo, bar: persistedBar }

hardSet

The persisted state will hard set the initial state. Any initial state defined in the reducers will be ignored.

  • Persisted state: { foo: persistedFoo }
  • Reducer initial state: { foo: reducerInitialFoo, bar: reducerInitialBar }
  • Reconciled state: { foo: persistedFoo }

Note how reducer’s initial state is completely ignored.

autoMergeLevel2

Not too sure how this works. Consult docs.

Whitelist or blacklist state slices

You can specify the set of state slices you don’t want to persist (blacklist):

const persistConfig = {
  key: 'root',
  storage: storage,
  blacklist: ['navigation'] // navigation will not be persisted
}

Or specify the set of slices you want to persist (whitelist)

const persistConfig = {
  key: 'root',
  storage: storage,
  whitelist: ['navigation'] // only navigation will be persisted
}

How to use with Redux Toolkit

Redux Toolkit uses the serializability middleware that warns (via console.warn) if you’re using any non-serializable values in your state or in dispatched actions. You’ll want to suppress these warnings by doing something like this:

import { configureStore } from '@reduxjs/toolkit'
import {
  persistStore,
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import { PersistGate } from 'redux-persist/integration/react'
import App from './App'
import rootReducer from './reducers'
const persistConfig = {
  key: 'root',
  version: 1,
  storage,
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
})
let persistor = persistStore(store)
ReactDOM.render(
  <Provider store={store}>
    <PersistGate loading={null} persistor={persistor}>
      <App />
    </PersistGate>
  </Provider>,
  document.getElementById('root')
)

See the docs and this GitHub issue for more guidance.

Other notes

Sources

Tagged: Redux