'How to configure redux-persist with redux-toolkit?
I have configured redux-persist with a traditional react-redux setup like this:
onst persistConfig = {
key: 'root',
storage,
whitelist: ['todos'],
};
const persistedReducer = persistReducer(persistConfig, reducer);
const store = createStore(
persistedReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
const persistor = persistStore(store);
// wrapper
const StateProvider = ({ children }) => {
return (
<Provider store={store}>
<PersistGate loading={<div>Loading...</div>} persistor={persistor}>
{children}
</PersistGate>
</Provider>
);
};
But, how can I configure it with redux-toolkit? So far I have tried this:
const persistedReducer = persistReducer(persistConfig, todoreducer);
const store = configureStore({
reducer: {
todos: persistedReducer,
},
});
const persistor = persistStore(store);
// wrapper
const StateProvider = ({ children }) => {
return (
<Provider store={store}>
<PersistGate loading={<div>Loading...</div>} persistor={persistor}>
{children}
</PersistGate>
</Provider>
);
};
But, It is not working. I can't get the todos
by const todos = useSelector(state => state.todos);
it returns undefined.
Solution 1:[1]
store.js
import {configureStore} from '@reduxjs/toolkit';
import storage from 'redux-persist/lib/storage'
import {combineReducers} from "redux";
import { persistReducer } from 'redux-persist'
import thunk from 'redux-thunk'
const reducers = combineReducers({
//...
});
const persistConfig = {
key: 'root',
storage
};
const persistedReducer = persistReducer(persistConfig, reducers);
const store = configureStore({
reducer: persistedReducer,
devTools: process.env.NODE_ENV !== 'production',
middleware: [thunk]
});
export default store;
Index/App.js
import store from './app/store';
import { PersistGate } from 'redux-persist/integration/react'
import { persistStore } from 'redux-persist'
let persistor = persistStore(store);
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App/>
</PersistGate>
</Provider>,
Solution 2:[2]
There's now a guide in the Redux Toolkit docs that will help you with this, as well as providing advice for purging the persisted state and working with RTK Query.
It also has some code you'll want to copy and paste to ignore the action types react-persist
dispatches. This will stop it throwing error messages (I was getting the error A non-serializable value was detected in an action, in the path: `register`.
when I ran my React Native app with Expo).
At time of writing, their code sample looks like this:
import { configureStore } from '@reduxjs/toolkit'
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import { PersistGate } from 'redux-persist/integration/react'
import App from './App'
import rootReducer from './reducers'
const persistConfig = {
key: 'root',
version: 1,
storage,
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}),
})
let persistor = persistStore(store)
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById('root')
)
Solution 3:[3]
When using TypeScript with stateReconciles
option from persistConfig
, you need a little type shim to avoid
- a)
unknown
generic inference
persistReducer<unknown, AnyAction>
Argument of type 'Reducer<CombinedState<{ ... }>, AnyAction>' is not assignable to parameter of type 'Reducer<unknown, AnyAction>'.
Types of parameters 'state' and 'state' are incompatible.
Type 'unknown' is not assignable to type 'CombinedState<{ ... }>'.ts(2345)
- b) circular type reference
const persistConfig = {
stateReconciles: hardSet as RootState,
}
export type RootState = ReturnType<typeof store.getState> // Type alias 'RootState' circularly references itself.
The solution is in the extracted type CombinedState
, as follows:
import type { Reducer } from '@reduxjs/toolkit'
import { configureStore, combineReducers } from '@reduxjs/toolkit'
import { persistStore, persistReducer } from 'redux-persist'
import * as rp from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import hardSet from 'redux-persist/lib/stateReconciler/hardSet'
import createCollectionForm from './slices/CollectionFormSlice'
import auth from './slices/AuthSlice'
const persistConfig = {
key: 'root',
storage,
stateReconciles: hardSet as (inboundState: CombinedState) => CombinedState,
version: 1,
}
type CombinedState = typeof rootReducer extends Reducer<infer U, any> ? U : never
const rootReducer = combineReducers({
auth,
createCollectionForm,
})
const persistedReducer = persistReducer(persistConfig, rootReducer)
export const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [rp.FLUSH, rp.REHYDRATE, rp.PAUSE, rp.PERSIST, rp.PURGE, rp.REGISTER],
},
}),
})
export const persistor = persistStore(store)
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Manuj Kathuria |
Solution 2 | pipedreambomb |
Solution 3 | Qwerty |