You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 18:34:55