Stop 09 · State ManagementTopics · 3/7

Redux Persist

Part of the Frontend Developer Roadmap

In short

Refresh the page and your Redux store starts empty again. Redux Persist saves the parts of the store you choose and loads them back when the app starts.

A library that automatically saves your Redux store to storage (like localStorage) and rehydrates it on page load, so state survives refreshes.

The jaadu mascot photographs a whiteboard full of diagrams before it gets wiped.

Think of it like this

A photo of the whiteboard

Before class ends and the board gets wiped, someone clicks a photo. Next day the teacher looks at the photo and rewrites the board. Redux Persist takes that photo of your store into localStorage, then restores it when the app reloads.

Watch it happen

Save, refresh, restore

Store
persistReducer
localStorage
PersistGate

cart/addItem

1/5You add an item, and the action reaches the persisted root reducer.

The big ideas

What you need to know

persistReducer wraps a reducer

It saves that reducer's state to storage whenever it changes.

Rehydration on startup

persistStore reads the saved state back and dispatches a REHYDRATE action to put it in the store.

PersistGate waits

Wrap your UI in PersistGate so it renders only after the saved state has been restored.

whitelist and blacklist

Save only what makes sense, like the cart and theme, and skip things like loading flags.

See it in code

Walk through the code

ts
1import { combineReducers, configureStore } from "@reduxjs/toolkit";2import { persistReducer, persistStore, FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER } from "redux-persist";3import storage from "redux-persist/lib/storage"; // localStorage4import { cartReducer, uiReducer } from "./slices";5 6const root = combineReducers({ cart: cartReducer, ui: uiReducer });7const persisted = persistReducer({ key: "root", storage, whitelist: ["cart"] }, root);8 9export const store = configureStore({10  reducer: persisted,11  middleware: (getDefault) =>12    getDefault({ serializableCheck: { ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER] } }),13});14export const persistor = persistStore(store);15 16// <PersistGate loading={null} persistor={persistor}><App /></PersistGate>

1/4Combine the slices into one root reducer.

Only cart is saved. ignoredActions stops RTK's serializability check from warning about redux-persist's own actions. PersistGate comes from redux-persist/integration/react.

Save yourself the pain

Common mistakes

Oops

Persisting the whole store, loading flags and errors included.

Do this instead

Use whitelist so only lasting data is saved. A stale loading: true after a refresh is a classic bug.

Oops

Changing the shape of persisted state and shipping it as is.

Do this instead

Old saved data won't match anymore. Bump the version in the config and add a migrate function.

Oops

Persisting auth tokens to localStorage.

Do this instead

Any script on the page can read localStorage. Keep tokens in HttpOnly cookies instead.

Your mission

Make the cart survive a refresh

~25 min

Quick check

Your persist config has whitelist: ["cart"]. After a refresh, what comes back?

Go deeper

  1. 1Add Redux Persist to a Redux Toolkit store and confirm state survives a refresh.
  2. 2Learn `whitelist`/`blacklist` config to persist only specific slices.
  3. 3Understand the rehydration flow and why there's often a brief 'loading' state on startup.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge