React Vite SSR使用react-router-dom路由遇document未定义等错误求助
React Vite SSR 路由问题解决方案
核心问题分析
document is not defined错误:服务端渲染(SSR)处于 Node.js 环境,不存在浏览器的document对象,但BrowserRouter/createBrowserRouter依赖浏览器环境创建 history,在服务端执行这类代码会直接报错。useRoutes() 需在 Router 上下文错误:移除浏览器端路由组件后,客户端缺少 Router 上下文提供,导致路由无法正常解析。
分步解决方案
1. 抽离共享路由配置
创建单独的 src/routes.js 文件,统一定义路由结构,确保服务端和客户端路由规则完全一致:
import { Home } from './pages/Home'; import { Other } from './pages/Other'; import { NotFound } from './pages/NotFound'; import App from './App'; export const routes = [ { path: '/', element: <App />, errorElement: <NotFound />, children: [ { index: true, element: <Home /> }, // 根路由匹配Home页面 { path: 'other', element: <Other /> }, // "关于我们"等其他页面路由 ], }, ];
2. 修改共享路由入口组件 (src/index.jsx)
改为使用 useRoutes 渲染路由,依赖外层提供的 Router 上下文(服务端用 StaticRouter,客户端用 BrowserRouter):
import React from 'react'; import { useRoutes } from 'react-router-dom'; import { routes } from './routes'; export const Index = () => { const routeElement = useRoutes(routes); return routeElement; };
3. 修复服务端渲染入口 (src/entry-server.jsx)
使用服务端专用的 StaticRouter,传入请求 URL 确保服务端渲染对应路由内容:
import React from 'react'; import ReactDOMServer from 'react-dom/server'; import { StaticRouter } from 'react-router-dom/server'; import { Index } from '.'; export function render(url) { const html = ReactDOMServer.renderToString( <StaticRouter location={url}> <Index /> </StaticRouter> ); return { html }; }
4. 修复客户端渲染入口 (src/entry-client.jsx)
使用浏览器端专用的 BrowserRouter 提供路由上下文,确保客户端路由正常工作:
import './index.css'; import React from 'react'; import ReactDOM from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; import { Index } from './index'; ReactDOM.hydrateRoot( document.getElementById('root'), <React.StrictMode> <BrowserRouter> <Index /> </BrowserRouter> </React.StrictMode> );
可选:使用 RouterProvider 替代 BrowserRouter
如果偏好 React Router v6.4+ 的 RouterProvider 写法,可修改客户端入口为:
import './index.css'; import React from 'react'; import ReactDOM from 'react-dom/client'; import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import { routes } from './routes'; // 仅在客户端执行,依赖浏览器环境 const router = createBrowserRouter(routes); ReactDOM.hydrateRoot( document.getElementById('root'), <React.StrictMode> <RouterProvider router={router} /> </React.StrictMode> );
此时 src/index.jsx 可直接删除,无需额外的共享组件。
关键注意事项
- 服务端永远不要使用依赖浏览器 API 的路由组件(
BrowserRouter/createBrowserRouter),必须用StaticRouter。 - 客户端和服务端的路由配置必须完全一致,避免 hydration 不匹配问题。
- 404 页面(
NotFound)不要包含浏览器专属 API(如window/document),否则服务端渲染会报错。
内容的提问来源于stack exchange,提问作者Pablo
相关产品推荐
相关产品推荐

