Next.js页面切换时Redux状态丢失问题求助(已用redux-persist)
问题分析与解决方案
你的Redux状态在页面切换时丢失,核心原因是每次_app.tsx渲染都会创建新的Store和Persistor实例,导致之前的状态被重置。此外,Storage初始化逻辑存在重复判断,persistStore的回调调用也多余。以下是具体修正步骤:
1. 修改Store代码,实现单例模式
将Store改为单例,避免重复创建,同时简化Storage初始化:
import { combineReducers, configureStore } from '@reduxjs/toolkit'; import { persistReducer, persistStore, WebStorage, createWebStorage } from 'redux-persist'; import hubSlice from './hubSlice'; import api from './api'; import { ThunkAction, AnyAction } from '@reduxjs/toolkit'; export function createPersistStorage(): WebStorage { const isServer = typeof window === 'undefined'; if (isServer) { return { getItem() { return Promise.resolve(null); }, setItem() { return Promise.resolve(); }, removeItem() { return Promise.resolve(); } }; } return createWebStorage('local'); } // 直接复用createPersistStorage的逻辑,无需重复判断window const storage = createPersistStorage(); const reducer = combineReducers({ [hubSlice.name]: hubSlice.reducer, [api.reducerPath]: api.reducer }); const persistConfig = { key: 'primary', storage, whitelist: ['hub'] }; const persistedReducer = persistReducer(persistConfig, reducer); // 单例Store实例 let store: ReturnType<typeof makeStore> | undefined; export const makeStore = () => { if (!store) { store = configureStore({ reducer: persistedReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false }).concat(api.middleware) }); } return store; }; export type AppStore = ReturnType<typeof makeStore>; export type AppState = ReturnType<AppStore['getState']>; export type AppDispatch = AppStore['dispatch']; export type AppThunk<ReturnType = void> = ThunkAction< ReturnType, AppState, unknown, AnyAction >; // 单例Persistor实例 export const getPersistor = () => { const store = makeStore(); return persistStore(store); };
2. 优化_app.tsx,缓存Store和Persistor
使用useMemo缓存实例,避免每次渲染重新创建:
import { Provider } from 'react-redux'; import { PersistGate } from 'redux-persist/integration/react'; import { makeStore, getPersistor } from '../store'; import { AppProps } from 'next/app'; import CssBaseline from '@mui/material/CssBaseline'; import { ThemeProvider } from '@mui/material/styles'; import staplesTheme from '../theme'; import { SnackbarProvider } from 'notistack'; import { useMemo } from 'react'; const MyApp = ({ Component, pageProps }: AppProps) => { // 缓存Store,确保全局唯一 const store = useMemo(() => makeStore(), []); // 缓存Persistor,与Store绑定 const persistor = useMemo(() => getPersistor(), [store]); return ( <Provider store={store}> <PersistGate loading={null} persistor={persistor}> <CssBaseline /> <ThemeProvider theme={staplesTheme}> <SnackbarProvider autoHideDuration={6000} preventDuplicate> <Component {...pageProps} /> </SnackbarProvider> </ThemeProvider> </PersistGate> </Provider> ); }; export default MyApp;
关键修复点说明
- 单例Store:全局仅维护一个Store实例,页面切换时状态不会被重置。
- 简化Storage逻辑:
createPersistStorage已经处理了服务端/客户端差异,无需重复判断window。 - 移除多余的
persistor.persist():persistStore初始化后会自动处理持久化,手动调用会导致冗余操作。 - 缓存Persistor:通过
useMemo确保Persistor与Store实例绑定,避免重复初始化。
内容的提问来源于stack exchange,提问作者rob111
相关产品推荐
相关产品推荐

