React同构应用报错:document is not defined 及渲染问题求助
同构React应用:解决ReferenceError: document is not defined及渲染异常问题
问题根源
你的服务端渲染报错核心原因是:服务端执行renderToString时,App组件内部嵌套了仅适用于客户端的BrowserRouter。BrowserRouter依赖浏览器环境的document对象处理路由逻辑,而Node.js服务端不存在该对象,直接触发ReferenceError。
虽然你在client.js里做了环境判断,但服务端渲染阶段已经会执行App组件内的BrowserRouter代码,这部分判断覆盖不到。
修复步骤
1. 重构App组件,抽离Router逻辑
修改src/components/App.jsx,移除内部的BrowserRouter,只保留路由配置:
import React from 'react'; import { Routes, Route } from 'react-router-dom'; import Home from './Home'; import Archive from './Archive'; const App = () => ( <Routes> <Route path="/" element={<Home />} /> <Route path="/archive" element={<Archive />} /> </Routes> ); export default App;
2. 在客户端入口包裹BrowserRouter
更新src/client.js,用BrowserRouter包裹App组件(仅在客户端执行):
import React from 'react'; import ReactDOM from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; import App from './components/App'; if (typeof window !== 'undefined') { const root = document.getElementById('root'); if (root) { ReactDOM.createRoot(root).render( <BrowserRouter> <App /> </BrowserRouter> ); } }
3. 确认服务端的StaticRouter配置
你的server.js中已经正确使用StaticRouter包裹App,保持现有逻辑即可:
const appString = renderToString( <StaticRouter location={req.url} context={context}> <App /> </StaticRouter> );
4. 检查页面组件的环境兼容性
如果Home或Archive组件中有直接访问window/document的代码(比如获取窗口尺寸、操作DOM),需要用useEffect延迟执行(useEffect仅在客户端渲染时触发):
// 错误示例(服务端会报错) const Home = () => { const width = window.innerWidth; return <div>窗口宽度:{width}</div>; }; // 正确写法 import { useEffect, useState } from 'react'; const Home = () => { const [width, setWidth] = useState(0); useEffect(() => { setWidth(window.innerWidth); }, []); return <div>窗口宽度:{width}</div>; };
验证修复
重新执行npm start,服务端渲染时会使用StaticRouter处理路由(不依赖浏览器环境),客户端 hydration 时用BrowserRouter接管,即可解决document is not defined错误和渲染异常问题。
内容的提问来源于stack exchange,提问作者Pluto
相关产品推荐
相关产品推荐

