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
排查修复方案
修正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 <>{/* 组件内容 */}</>; }确保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> ); }检查auth状态的可序列化性
redux-persist要求存储的状态必须是可序列化的,如果auth状态里包含函数、Symbol、循环引用这类不可序列化的值,会导致rehydrate失败,进而引发组件挂载异常。
解决:检查auth reducer的状态结构,移除所有不可序列化的内容,确保状态能被正常转为JSON。排除热重载干扰
错误日志里提到了HotReload组件,开发环境的热重载可能和redux-persist存在冲突。可以尝试关闭热重载,或者打包生产版本测试,看是否还会出现白屏。
内容的提问来源于stack exchange,提问作者Alikula
相关产品推荐
相关产品推荐

