How to persist Redux State after closing and reopening a React application

The default behavior after closing a React behavior or any website for that matter is for the page’s local state to be lost. In a Single Page Application framework such as React this could mean you are logged out or certain setting changes are lost. This blog post explains how to persist state using the npm package redux-persist, it assumes that you have a React application which manages it’s state with Redux.

Install the package into your application

Luckily there is an npm package for this problem called redux-persist this package. This package works by taking your Redux reducer and persisting it’s data into storage of some form. This could be an API response (for advanced users) or by default to the browser’s local storage. You will need to install the package before you can start using it. Use the package manager you prefer, I use npm so will run npm install redux-persist.

Update your React root component

For most people this file is called App.js you’ll need to update it to use redux-persist‘s PersistGate. This is a wrapper component which prevents the rest of the application from loading until state is restored from storage. For those who load it from an API you can provide an optional loading component. For simplicity I did not include react-router in my example, however it should be nested inside of the PersistGate if you need to use it. Your React root component should look something like this.

import React from 'react';
import ReactDOM from 'react-dom';
import * as serviceWorker from './serviceWorker';
import {Provider} from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor} from './store';
import './style/App.css';

ReactDOM.render(
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

Update your reducer

You will need to use redux-persist‘s persistedReducer() method to load in your reducer, this allows it load in your state after loading in the initial state. As recommended by the Redux Developers I use the Redux Toolkit, if you haven’t used it before I highly recommend checking it out. As a brief overview the slice is an object managed by the Redux Toolkit which exports your actions and your reducer. redux-persist does not care where the reducer is, only that you load it through redux-persist‘s persistedReducer() method. The end result will look something like this.

import { configureStore } from '@reduxjs/toolkit';
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import  slice  from "./slice";

const persistConfig = {
    key: 'root',
    storage,
    blacklist: [
        'featureFlags`,
        'temporaryDataSuchAsPasswords',
    ]
};

const reducer = slice.reducer;
const actions = slice.actions;

const persistedReducer = persistReducer(persistConfig, reducer);

export const store = configureStore({ reducer: persistedReducer });
export const persistor = persistStore(store);

export const { actionNamesGoHere } = actions;

Complete

Once your application loads through the PersistGate component and the reducer is loaded through redux-persist‘s resistReducer() method you’re all done and your app will now persist its Redux state into local storage. For more information check out the README file which explains storage and persistor options for advanced use cases.