Persisting State in React App with Redux Persist

Redux Persist is a library used to save the Redux store’s state to persistent storage, such as local storage, and rehydrate it when the app loads. In this article, we make a simple counter application using React and Redux, demonstrating state persistence using Redux Persist. This project includes incrementing, decrementing, and resetting the counter value functionalities.

Working on Redux Persist Library

  1. Serialization: Whenever the Redux state changes, then Redux Persist intercepts your Redux store’s state and converts it into a format suitable for storage like JSON string.
  2. Store State : After serialization Redux Persist save this data to a specified storage (e.g., local storage).
  3. Rehydration: When the application loads, Redux Persist retrieves the persisted state from storage and injects it back into the Redux store before rendering the UI.

Approach

  • Project Setup : Create a React Application and install required module like “redux-persist”.
  • Set Up Redux Store with Persistence : Create an initial state and reducer for the counter, configure Redux Persist to use local storage, and create the Redux store with the persisted reducer and persistor.
  • Counter Component : Create a Counter component and manage state with useSelector and useDispatch.
  • Setup Redux Provider and PersistGate : Wrap the application in Provider to pass the store and PersistGate to ensure the persisted state is loaded before rendering the UI.

Steps to Create Application

Step 1: Create a React application using the following command.

npx create-react-app redux-persist-app

Step 2: After creating your project folder i.e. redux-persist-app, move to it using the following command.

cd redux-persist-app

Step 3 : Install required dependencies like redux-persist, and redux.

npm install redux react-redux redux-persist

Project Structure:

Project Structure

Updated dependencies in package.json file

 "dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"redux-persist": "^6.0.0",
},

Example: To demonstrate the implementation of the persisting state in a react-redux application by creating a simple counter app.

CSS
/* App.css */
button {
  padding: 10px 20px;
  background-color: rgba(204, 207, 205, 0.74);
  margin: 10px 5px;
  cursor: pointer;
}
button:hover {
  background-color: rgba(9, 221, 9, 0.788);
}
#App {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
JavaScript
// store.js 
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';

//   initial state
const initialState = {
    value: 0,
};

//  reducer
const counterReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return { ...state, value: state.value + 1 };
        case 'DECREMENT':
            return { ...state, value: state.value - 1 };
        case 'RESET':
            return { ...state, value: 0 };
        default:
            return state;
    }
};

// Persist configuration
const persistConfig = {
    key: 'root',
    storage,
};

// Create a persisted reducer
const persistedReducer = persistReducer(persistConfig, counterReducer);

// Create the Redux store
export const store = createStore(persistedReducer);

// Create a persistor
export const persistor = persistStore(store);
JavaScript
// App.js 
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import './App.css'

const Counter = () => {
  const count = useSelector((state) => state.value);
  const dispatch = useDispatch();
  return (
    <div id='App'>
      <h1><img src='https://media.w3wiki.net/gfg-gg-logo.svg' alt='gfg_logo' /> {"   "} Counter: {count}</h1>
      <div>
        <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
        <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
        <button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
      </div>
    </div>
  );
};

export default Counter;
JavaScript
// index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from './store';
import { Provider } from 'react-redux';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <PersistGate loading={null} persistor={persistor}>
      <div className="App">
        <App />
      </div>
    </PersistGate>
  </Provider>
);

Output