I am creating an application on Next js. I use redux-toolkit and next-redux-wrapper in it, I want to save the contents of my store in localStorage. But I ran into a problem - an object from redux-persist appears in the developer console, but its contents do not change when dispatch calls and store changes.
my store
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist'
import storage from 'redux-persist/lib/storage'
const makeStore = () => {
const isServer = typeof window === 'undefined';
const rootReduser = combineReducers(
{
search: searchDataReduser,
userData: userDataReduser,
regions: regionsIdReduser,
loading: visibleLoadingReduser,
hotelsRegion: hotelsRegionReduser,
hotelsId: hotelsIdReduser,
room: roomBookingReduser,
webRoom: webRoomBookingReduser,
bookingRoomData: bookingRoomsUserDataReduser
}
)
if (isServer) {
const store = configureStore({
reducer: rootReduser,
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
immutableCheck: false,
serializableCheck: false
})
})
return store
} else {
const persistConfig = {
key: "nextjs",
storage
}
const persistedReducer = persistReducer(persistConfig, rootReduser)
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
immutableCheck: false,
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
}
})
})
return store
}
}
export const store = makeStore()
export const persistor = persistStore(makeStore())
export type RootStore = ReturnType<typeof makeStore>;
export type RootState = ReturnType<RootStore['getState']>;
export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, RootState, unknown, Action>;
export type AppDispatch = typeof store.dispatch
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const wrapper = createWrapper<RootStore>(makeStore);
my app component
function App({ Component, pageProps }: AppProps) {
const loading = useAppSelector(state => state.loading.loading)
const dispatch = useDispatch()
const router = useRouter()
useEffect(() => {
router.events.on('routeChangeStart', (url) => {
dispatch(visibleLoadingFunction(true))
})
router.events.on('routeChangeComplete', (url) => {
dispatch(visibleLoadingFunction(false))
})
}, [])
return (
<>
<PersistGate persistor={persistor} loading={<div>Loading...</div>}>
<Head>
<link rel="icon" href={'./favicon.svg'} type="image/svg" />
</Head>
<div className='wrapper'>
{loading && <LoadingRouter />}
<Component {...pageProps} />
</div>
</PersistGate>
</>
)
}
App.getInitialProps = wrapper.getInitialAppProps(store => async ({ ctx, Component }) => {
try {
//контент
} catch (err) {
//контент
}
return {
pageProps: Component.getInitialProps ? await Component.getInitialProps({ ...ctx, store }) : {}
}
})
export default wrapper.withRedux(App)
One of the Reduser
const initialState: searchStateType = {
dataBar:
{
location: '',
date: {
from: undefined,
to: undefined
},
number: {
adults: 1,
child: 0,
rooms: 1
}
}
}
const searchDataSlice = createSlice({
name: 'search',
initialState,
reducers: {
searchbar: (state, action: PayloadAction<searchStateType>) => {
state.dataBar = { ...action.payload.dataBar }
}
},
extraReducers: {
[HYDRATE]: (state, action) => {
return {
...state,
...action.payload.search
}
}
}
})
export const { searchbar } = searchDataSlice.actions
export default searchDataSlice.reducer
CodePudding user response:
As per the documentation, call persistStore
within makeStore
:
const makeStore = () => {
const isServer = typeof window === "undefined";
const rootReduser = combineReducers({
search: searchDataReduser,
userData: userDataReduser,
regions: regionsIdReduser,
loading: visibleLoadingReduser,
hotelsRegion: hotelsRegionReduser,
hotelsId: hotelsIdReduser,
room: roomBookingReduser,
webRoom: webRoomBookingReduser,
bookingRoomData: bookingRoomsUserDataReduser,
});
if (isServer) {
const store = configureStore({
reducer: rootReduser,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
immutableCheck: false,
serializableCheck: false,
}),
});
return store;
} else {
const persistConfig = {
key: "nextjs",
storage,
};
const persistedReducer = persistReducer(persistConfig, rootReduser);
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
immutableCheck: false,
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}),
});
store.__persistor = persistStore(store); // Nasty hack
return store;
}
};
and then remove those top-level lines:
export const store = makeStore();
export const persistor = persistStore(makeStore());
and in your App
component, get the persistor from the store:
<ReactReduxContext.Consumer>
{({ store }) => (
<PersistGate persistor={store.__persistor} loading={<div>Loading</div>}>
<Head>
<link rel="icon" href={"./favicon.svg"} type="image/svg" />
</Head>
<div className="wrapper">
{loading && <LoadingRouter />}
<Component {...pageProps} />
</div>
</PersistGate>
)}
</ReactReduxContext.Consumer>