如何在Next.js中使用BrowserRouter且避免‘document is not defined’报错?
Next.js使用BrowserRouter出现
document is not defined错误解决方案 错误信息
ReferenceError: document is not defined at getUrlBasedHistory (C:\Users\simer\Downloads\Talkhappi\client\node_modules\@remix-run\router\dist\router.cjs.js:380:14) at Object.createBrowserHistory (C:\Users\simer\Downloads\Talkhappi\client\node_modules\@remix-run\router\dist\router.cjs.js:207:10) at BrowserRouter (C:\Users\simer\Downloads\Talkhappi\client\node_modules\react-router-dom\dist\umd\react-router-dom.development.js:256:35) at processChild (C:\Users\simer\Downloads\Talkhappi\client\node_modules\react-dom\cjs\react-dom-server.node.development.js:3043:14) at resolve (C:\Users\simer\Downloads\Talkhappi\client\node_modules\react-dom\cjs\react-dom-server.node.development.js:2960:5) at ReactDOMServerRenderer.render (C:\Users\simer\Downloads\Talkhappi\client\node_modules\react-dom\cjs\react-dom-server.node.development.js:3435:22) at ReactDOMServerRenderer.read (C:\Users\simer\Downloads\Talkhappi\client\node_modules\react-dom\cjs\react-dom-server.node.development.js:3373:29) at renderToString (C:\Users\simer\Downloads\Talkhappi\client\node_modules\react-dom\cjs\react-dom-server.node.development.js:3988:27) at Object.renderPage (C:\Users\simer\Downloads\Talkhappi\client\node_modules\next\dist\next-server\server\render.js:50:851) at Function.getInitialProps (C:\Users\simer\Downloads\Talkhappi\client\.next\server\pages\_document.js:299:19)
现有代码
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' import { useAuthContext } from 'hooks/useAuthContext'; import HomePage from './home'; import ProductPage from './product'; import LoginPage from './login'; import SignupPage from './signup'; export default function IndexPage() { const { user } = useAuthContext() return ( <div> <BrowserRouter> <div> <Routes> <Route path="/" element={<HomePage />} /> <Route path="/login" element={!user ? <LoginPage /> : <Navigate to="/" />} /> <Route path="/signup" element={!user ? <SignupPage /> : <Navigate to="/" />} /> <Route path="/product" element={!user ? <ProductPage /> : <Navigate to="/" />} /> </Routes> </div> </BrowserRouter> </div> ); }
问题原因
Next.js默认是服务端渲染(SSR),在服务端Node.js环境中不存在浏览器的document对象,而BrowserRouter初始化时会直接访问document,导致服务端渲染阶段报错。
解决方案
方案1:改用Next.js原生路由系统(推荐)
Next.js自带完善的路由机制(Pages Router或App Router),无需依赖react-router-dom,更适配SSR场景。
以Pages Router为例,实现登录状态路由守卫:
- 在
pages/_app.js中添加全局路由逻辑:
import { useAuthContext } from 'hooks/useAuthContext'; import { useEffect } from 'react'; import { useRouter } from 'next/router'; function MyApp({ Component, pageProps }) { const { user } = useAuthContext(); const router = useRouter(); useEffect(() => { // 定义需要登录才能访问的路由 const protectedRoutes = ['/product']; // 定义已登录用户不能访问的路由 const authRoutes = ['/login', '/signup']; // 未登录且访问保护路由,跳转到登录页 if (!user && protectedRoutes.includes(router.pathname)) { router.push('/login'); } // 已登录且访问登录/注册页,跳转到首页 else if (user && authRoutes.includes(router.pathname)) { router.push('/'); } }, [user, router]); return <Component {...pageProps} />; } export default MyApp;
- 按照Next.js Pages Router规则组织页面:
pages/index.js对应首页(HomePage)pages/login.js对应登录页(LoginPage)pages/signup.js对应注册页(SignupPage)pages/product.js对应产品页(ProductPage)
方案2:将BrowserRouter限定在客户端执行(仅特殊场景使用)
如果必须使用react-router-dom,可以通过Next.js的客户端组件指令'use client',让BrowserRouter只在浏览器环境运行:
- 创建客户端路由组件
ClientRouter.js:
'use client'; import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; import { useAuthContext } from 'hooks/useAuthContext'; import HomePage from './home'; import ProductPage from './product'; import LoginPage from './login'; import SignupPage from './signup'; export default function ClientRouter() { const { user } = useAuthContext(); return ( <BrowserRouter> <Routes> <Route path="/" element={<HomePage />} /> <Route path="/login" element={!user ? <LoginPage /> : <Navigate to="/" />} /> <Route path="/signup" element={!user ? <SignupPage /> : <Navigate to="/" />} /> {/* 修正原代码逻辑:产品页应该是登录后才能访问 */} <Route path="/product" element={user ? <ProductPage /> : <Navigate to="/login" />} /> </Routes> </BrowserRouter> ); }
- 在
pages/index.js中引入该组件:
import ClientRouter from './ClientRouter'; export default function IndexPage() { return <ClientRouter />; }
注意:这种方式会放弃Next.js的SSR优势,且可能与Next.js原生路由产生冲突,非必要不推荐使用。
内容的提问来源于stack exchange,提问作者Soccerball123
相关产品推荐
相关产品推荐

