How to Persist Redux State Using Local Storage in React
Maintaining state across page reloads in React Redux apps can be tricky. Thankfully, local storage offers a simple and effective way to persist your Redux state, ensuring that users’ data remains intact even when they refresh the page or reopen the browser. In this guide, we’ll walk through the steps to persist and rehydrate your Redux state using local storage.
Why Persist Redux State?
Persisting Redux state is particularly useful for retaining user preferences, themes, and settings, saving form data or shopping cart contents across reloads, and providing a seamless user experience without requiring a backend.
Setup and Prerequisites
Before we begin, make sure you have the following:
A React app set up with Redux. If not, initialize it by installing the required packages:
npm install redux react-redux
- Step 1: Create Utility Functions for Local Storage
We’ll create two utility functions: one to save state to local storage and another to load state from it.
// src/utils/localStorage.js
export const loadState = () => {
try {
const serializedState = localStorage.getItem('reduxState')
if (serializedState === null) {
return undefined // Let reducers initialize their default state
}
return JSON.parse(serializedState)
} catch (err) {
console.error('Failed to load state from localStorage', err)
return undefined
}
}
export const saveState = (state) => {
try {
const serializedState = JSON.stringify(state)
localStorage.setItem('reduxState', serializedState)
} catch (err) {
console.error('Failed to save state to localStorage', err)
}
}
- Step 2: Integrate Local Storage with Redux Store
In your Redux store configuration, use the loadState
function to initialize the store with the persisted state. Then, subscribe to store changes to save the state to local storage whenever it updates.
// src/store.js
import { createStore } from 'redux'
import rootReducer from './reducers'
import { loadState, saveState } from './utils/localStorage'
// Load persisted state
const persistedState = loadState()
// Create the Redux store
const store = createStore(
rootReducer,
persistedState, // Initialize store with persisted state
)
// Subscribe to store updates to save state to local storage
store.subscribe(() => {
saveState(store.getState())
})
export default store
- Step 3: InUse the Store in Your Application
Wrap your application with the Provider
from react-redux
, passing the store as a prop.
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import store from './store'
import App from './App'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
)
Tips and Considerations
- Selective Persistence: If you don’t want to persist the entire Redux state, you can save only specific slices of it. For example:
saveState({
user: state.user,
cart: state.cart,
})
-
Avoid Storing Sensitive Data: Local storage is not secure for sensitive information like authentication tokens or passwords.
-
State Size: Local storage has a storage limit (usually 5MB). Be mindful of the amount of data you’re persisting.
-
Debouncing: To avoid performance issues, debounce the
saveState
function to limit how often it’s called.
import debounce from 'lodash.debounce'
store.subscribe(
debounce(() => {
saveState(store.getState())
}, 1000),
)
Conclusion
Persisting Redux state using local storage is a straightforward way to enhance user experience in React applications. With just a few utility functions and minor modifications to your Redux setup, you can ensure that your application’s state survives browser reloads and retains critical user data.