如何在无SSR的React Router v7 Framework模式中使用redux-persist与RTK?
React Router v7 Framework模式下redux-persist存储报错解决
问题描述
将React/Vite应用迁移至React Router v7 Framework模式后,执行npm run dev时出现以下错误:
redux-persist failed to create sync storage. falling back to noop storage. [vite] (ssr) Error when evaluating SSR module virtual:react-router/server-build: storage.getItem is not a function ... [vite] Internal server error: storage.getItem is not a function
可通过以下步骤复现:
- 执行
npx create-react-router@latest创建全新应用 - 配置
react-router.config.ts关闭SSR:
import type { Config } from "@react-router/dev/config"; export default { ssr: false, } satisfies Config;
- 创建Redux store及切片:
./app/store/store.js
import { configureStore } from "@reduxjs/toolkit"; import storage from "redux-persist/lib/storage"; import { persistReducer, persistStore } from "redux-persist"; import auth from "./authSlice"; const persistConfig = { key: "root", storage, }; export const reducer = persistReducer(persistConfig, auth); export const store = configureStore({ reducer }); export const persistor = persistStore(store);
./app/store/authSlice.js
import { createSlice } from "@reduxjs/toolkit"; export const authSlice = createSlice({ name: "auth", initialState: { token: "" }, reducers: { setToken(state, action) { state.token = action.payload; }, }, }); export default authSlice.reducer;
- 修改
root.tsx添加Redux Provider:
import { Provider } from "react-redux"; import { store } from "./store/store"; import { Outlet } from "react-router"; export default function App() { return ( <Provider store={store}> <Outlet /> </Provider> ); }
解决方案
无需替换redux-persist,通过环境兼容的存储引擎配置和客户端延迟初始化即可解决问题:
1. 适配环境的存储引擎配置
修改./app/store/store.js,根据运行环境选择存储引擎:Node环境使用noop存储(不做持久化),浏览器环境使用localStorage:
import { configureStore } from "@reduxjs/toolkit"; import { persistReducer, persistStore } from "redux-persist"; import createNoopStorage from "redux-persist/lib/storage/noop"; import auth from "./authSlice"; // 根据环境动态选择存储引擎 const storage = typeof window !== "undefined" ? require("redux-persist/lib/storage").default : createNoopStorage(); const persistConfig = { key: "root", storage, }; export const reducer = persistReducer(persistConfig, auth); export const store = configureStore({ reducer }); // 仅在客户端初始化persistStore export let persistor; if (typeof window !== "undefined") { persistor = persistStore(store); }
2. 客户端延迟初始化PersistGate(若使用)
如果你的应用使用PersistGate,需确保它仅在客户端渲染时加载,修改root.tsx:
import { Provider } from "react-redux"; import { store } from "./store/store"; import { PersistGate } from "redux-persist/integration/react"; import { useEffect, useState } from "react"; import { Outlet } from "react-router"; export default function App() { const [clientPersistor, setClientPersistor] = useState(null); useEffect(() => { // 在客户端环境初始化persistor import("./store/store").then((module) => { setClientPersistor(module.persistor); }); }, []); // 客户端未初始化完成时,直接渲染内容或加载态 if (!clientPersistor) { return <Outlet />; } return ( <Provider store={store}> <PersistGate loading={null} persistor={clientPersistor}> <Outlet /> </PersistGate> </Provider> ); }
3. 确认SSR配置生效
确保react-router.config.ts中的ssr: false配置正确,避免不必要的SSR预渲染流程:
import type { Config } from "@react-router/dev/config"; export default { ssr: false, } satisfies Config;
原理说明
错误根源是redux-persist在Node环境(SSR评估阶段)尝试访问浏览器专属的localStorage API,而Node环境不存在该接口。即使关闭SSR,React Router Framework模式在启动时仍会执行模块评估,导致store初始化时触发storage访问。通过环境判断切换存储引擎,避免在Node环境调用浏览器API,即可解决该问题。
内容的提问来源于stack exchange,提问作者drosboro
相关产品推荐
相关产品推荐

