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

Next.js集成Redux Toolkit与Redux Persist后白屏及useRouter异常

问题描述

应用编译后出现空白白屏,无法完成挂载,刷新也无效。添加redux-persist持久化auth状态后触发了该问题,同时影响了登录路由处理用到的useRouter Hook。以下是我的Store代码:

/* Core */
import {
  configureStore,
  type ThunkAction,
  type Action,
} from "@reduxjs/toolkit";
import {
  useSelector as useReduxSelector,
  useDispatch as useReduxDispatch,
  type TypedUseSelectorHook,
} from "react-redux";
import { persistStore, persistReducer } from "redux-persist";

/* Instruments */
import { rootReducer } from "./reducers";
import { middleware } from "./middleware";
import storage from "redux-persist/lib/storage";
import {
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from "redux-persist";

const persistConfig = {
  key: "root",
  storage,
  whitelist: ["auth"],
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const reduxStore = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) => {
    return getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }).concat(middleware);
  },
});

export const persistore = persistStore(reduxStore);

persistore.subscribe(() => {
  console.log("Actions during persist:", reduxStore.getState());
});

export const useDispatch = () => useReduxDispatch<ReduxDispatch>();
export const useSelector: TypedUseSelectorHook<ReduxState> = useReduxSelector;

/* Types */
export type ReduxStore = typeof reduxStore;
export type ReduxState = ReturnType<typeof reduxStore.getState>;
export type ReduxDispatch = typeof reduxStore.dispatch;
export type ReduxThunkAction<ReturnType = void> = ThunkAction<
  ReturnType,
  ReduxState,
  unknown,
  Action
>;

错误日志

at useRouter (navigation.js:125:15)
    at HotReload (hot-reloader-client.js:355:46)
    at renderWithHooks (react-dom.development.js:11009:18)
    at mountIndeterminateComponent (react-dom.development.js:16761:13)
    at beginWork$1 (react-dom.development.js:18345:16)
    at HTMLUnknownElement.callCallback (react-dom.development.js:20461:14)
    at Object.invokeGuardedCallbackImpl (react-dom.development.js:20510:16)
    at invokeGuardedCallback (react-dom.development.js:20585:29)
    at beginWork (react-dom.development.js:26763:7)
    at performUnitOfWork (react-dom.development.js:25587:12)
    at workLoopSync (react-dom.development.js:25303:5)
    at renderRootSync (react-dom.development.js:25258:7)
    at performConcurrentWorkOnRoot (react-dom.development.js:24382:74)
    at workLoop (scheduler.development.js:261:34)
    at flushWork (scheduler.development.js:230:14)
    at MessagePort.performWorkUntilDeadline (scheduler.development.js:534:21)
useRouter @ navigation.js:125
HotReload @ hot-reloader-client.js:355
renderWithHooks @ react-dom.development.js:11009
mountIndeterminateComponent @ react-dom.development.js:16761
beginWork$1 @ react-dom.development.js:18345
callCallback @ react-dom.development.js:20461
invokeGuardedCallbackImpl @ react-dom.development.js:20510
invokeGuardedCallback @ react-dom.development.js:20585

排查修复方案

  1. 修正useRouter的使用场景
    useRouter只能在React组件或自定义Hook内部调用,绝对不能在redux的persist回调、store初始化这类非组件上下文里使用。如果你的auth逻辑里有在persist完成后直接调用useRouter跳转的代码,会直接触发报错。
    解决:把路由跳转逻辑移到组件内部,比如用useEffect监听auth状态变化,再执行跳转:

    import { useRouter } from 'next/router';
    import { useSelector } from './store';
    
    function AuthGuard() {
      const router = useRouter();
      const { isAuthenticated } = useSelector(state => state.auth);
    
      useEffect(() => {
        if (!isAuthenticated) {
          router.push('/login');
        }
      }, [isAuthenticated, router]);
    
      return <>{/* 组件内容 */}</>;
    }
    
  2. 确保store完成持久化后再渲染应用
    白屏大概率是因为persist的rehydrate过程还没完成,就渲染了依赖store状态的组件。用redux-persist提供的PersistGate组件包裹应用,等待持久化完成后再渲染:

    import { Provider } from 'react-redux';
    import { PersistGate } from 'redux-persist/integration/react';
    import { reduxStore, persistore } from './store';
    import AppRouter from './router';
    
    function RootApp() {
      return (
        <Provider store={reduxStore}>
          <PersistGate loading={null} persistor={persistore}>
            <AppRouter />
          </PersistGate>
        </Provider>
      );
    }
    
  3. 检查auth状态的可序列化性
    redux-persist要求存储的状态必须是可序列化的,如果auth状态里包含函数、Symbol、循环引用这类不可序列化的值,会导致rehydrate失败,进而引发组件挂载异常。
    解决:检查auth reducer的状态结构,移除所有不可序列化的内容,确保状态能被正常转为JSON。

  4. 排除热重载干扰
    错误日志里提到了HotReload组件,开发环境的热重载可能和redux-persist存在冲突。可以尝试关闭热重载,或者打包生产版本测试,看是否还会出现白屏。

内容的提问来源于stack exchange,提问作者Alikula

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 03:35:38