When we refresh page in a web-app, the state always resets back to the initial values which in not a good thing when you try to build some large web-app like e-commerce.
We can manually do the state persistent using the native JavaScript localStorage.setItem()
method but honestly we will have to write everything from start and we have to maintain the structure of the state.
So here the redux-persist comes into play, with support for redux toolkit, that helps us to persist the state after page refresh.
Redux-Persist
It is a package for persisting redux state when it is connected to the store.
That's all what the package does. Pretty neat!
Without further talking, lets dive into how we actually hook it up with redux toolkit for state/store persisting. We will use a counter app for easier understanding.
Step 1:
Install the package via npm
or yarn
(I will use npm here):
npm i redux-persist
Step 2:
Add the required imports to the redux store:
//store.js
import storage from 'redux-persist/lib/storage';
import { combineReducers } from 'redux';
import {
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist';
redux-persist provides different storage to persist data like local storage, session storage or async storge. We will use the local storage.
We need the combineReducers
function to group up all the reducers into one so that we can pass it to the redux-persist.
redux-persist dispatches some functions and according to official redux-toolkit guide we need to add those to the ignore list to avoid unnecessary warnings or errors.
Step 3:
We need to create the persist object config that will be stored to the storage:
//store.js
const persistConfig = {
key: 'counter',
storage,
};
The key specifies the ID of the persist object and the storage determines the type of storage being used.
Step 4:
Combine the reducers:
//store.js
const reducers = combineReducers({ counter: counterSlice });
Step 5:
Create a persistent reducer:
///store.js
const persistedReducer = persistReducer(persistConfig, reducers);
Step 6:
Assign the persist reducer to the reducers and extra dispatch functions to the ignore list in the middleware, at the end your store will look like this:
//store.js
export default configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}),
});
Step 7:
Just like react-redux gives us Provider
component that will wrap the whole app, similarly we get PersistGate
from redux-persist. We need it to wrap around the whole app:
//index.js
import { persistStore } from 'redux-persist';
import { PersistGate } from 'redux-persist/integration/react';
//...
let persistor = persistStore(store);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<PersistGate persistor={persistor}>
<App />
</PersistGate>
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
The persistStore
will configure the store object to become compatible when we pass it to the PersistGate
component.
Step 8:
With all the connection done, now your react app can persist when when page changes and or the page reloads.
If we check it with redux-logger, we can see that it first checks with PERSIST
action and rehydrate the store with the REHYDRATE
action.
Wrapping Up
redux-persist is a great library for obvious reason, but it's way old and outdated, last update was at 2019 with several PR and issues at GitHub. I hope they revive the project and fix the necessary issues. Meanwhile, if you know any alternatives please let me know in the comments.
Top comments (2)
Hi, thank you this was helpful but there's an issue i'm having using this method, all the data that is persisted with redux-persist is the same across multiple browers and tabs. Let's say we have a dashboard, the data on the dashboards should vary depending on the particular user.
thank you.