Recently, I've discovered redux-toolkit
which is the official, opinionated, batteries-included toolset for efficient Redux development. It's intended to be the standard way to write Redux logic. Moreover, redux template for create-react-app
is now using redux-toolkit
by default.
Today, I'd like to share a way to use redux-persist
with redux-toolkit
. redux-persist
gives us an ability to save Redux store in the Local Storage of the browser. Effectively, when you press the refresh page button in your browser, your storage will remain the same. Obviously, you can define how many levels or which parts of your store you want to make persistent.
I will use a fresh copy of the create-react-app
with redux-toolkit
built-in and jump straight to the action.
1npx create-react-app my-app --template redux
We just genereated our create-react-app
and we got this file structure as an output.
1├── README.md2├── node_modules3├── package.json4├── public5├── src6└── yarn.lock
We are interested in /src/app
folder where we can find store.js
file.
1src2├── App.css3├── App.js4├── App.test.js5├── app6│ └── store.js7├── features8│ └── counter9│ ├── Counter.js10│ ├── Counter.module.css11│ └── counterSlice.js12├── index.css13├── index.js14├── logo.svg15├── serviceWorker.js16└── setupTests.js
Now, let's have a quick look at src/app/store.js
and src/index.js
files. These are 2 files where we will do all of the required changes.
1import { configureStore } from '@reduxjs/toolkit';2import counterReducer from '../features/counter/counterSlice';3
4export default configureStore({5 reducer: {6 counter: counterReducer,7 },8});
1// ...2
3import store from './app/store';4import { Provider } from 'react-redux';5
6ReactDOM.render(7 <React.StrictMode>8 <Provider store={store}>9 <App />10 </Provider>11 </React.StrictMode>,12 document.getElementById('root')13);14
15// ...
First of all, let's add redux-persist
as a package (we will need it later) and run the application in development mode.
1yarn add redux-persist2
3yarn start
Now, we should be up and running, and we should see our counter example application. You can test out the application to see how it works and then hit the page refresh button. Then the state is refreshed back to the normal and you should see 0 counts on the screen. But we want to keep it persistent, right? That's where redux-persist steps in!
Now let's do some changes to the following files.
The general idea is that on line 18
in src/app/store.js
you can define, which reducers
you want to make persistent. You need to carefully decide how many levels of state you want to "merge". The default is 1 level. More information - state reconciler docs.
1import { configureStore } from '@reduxjs/toolkit';2import storage from 'redux-persist/lib/storage';3import { combineReducers } from 'redux';4import { persistReducer } from 'redux-persist';5import thunk from 'redux-thunk';6
7import counterReducer from '../features/counter/counterSlice';8
9const reducers = combineReducers({10 counter: counterReducer,11});12
13const persistConfig = {14 key: 'root',15 storage,16};17
18const persistedReducer = persistReducer(persistConfig, reducers);19
20const store = configureStore({21 reducer: persistedReducer,22 devTools: process.env.NODE_ENV !== 'production',23 middleware: [thunk],24});25
26export default store;
Here we add persistStore
and PersistGate
. PersistGate
delays the rendering of your app's UI until your persisted state has been retrieved and saved to redux.
1// ...2
3import { PersistGate } from 'redux-persist/integration/react';4import { persistStore } from 'redux-persist';5
6let persistor = persistStore(store);7
8ReactDOM.render(9 <React.StrictMode>10 <Provider store={store}>11 <PersistGate loading={null} persistor={persistor}>12 <App />13 </PersistGate>14 </Provider>15 </React.StrictMode>,16 document.getElementById('root')17);18
19// ...
Now it's time to test our application! Try to increase or decrease the amount and then hit page refresh as well as open your developer console and check the local storage setting, where you should see the amount
value in it.
To prevent any performance issues, you can decide which parts of the state you want to persist. Take a look at the example below, and amend persistConfig
in src/app/store.js
as per your needs.
1// blacklist2const persistConfig = {3 key: 'root',4 storage: storage,5 blacklist: ['navigation'], // navigation will not be persisted6};7
8// whitelist9const persistConfig = {10 key: 'root',11 storage: storage,12 whitelist: ['navigation'], // only navigation will be persisted13};
To simplify things, I've added the code above into repository, which you can use as a starter template. Additionally, I've deployed it to Netlify so you could see it in action.
Sign up to get updates when I write something new. No spam ever.
Subscribe to my Newsletter