Next.js添加react-router-dom后npm run build预渲染报错求助
Next.js 引入 react-router-dom 构建预渲染报错解决方案
问题描述
在Next.js项目中引入react-router-dom后,开发环境运行正常,但执行npm run build部署应用时,预渲染根路径/时出现报错。
错误日志
Error at l (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\.next\server\app\page.js:10:343) at C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\.next\server\app\page.js:19:1632 at C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\.next\server\app\page.js:19:3359 at k (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\.next\server\app\page.js:19:3362) at nT (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\node_modules\next\dist\compiled\next-server\app-page.runtime.prod.js:12:46138) at nT (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\node_modules\next\dist\compiled\next-server\app-page.runtime.prod.js:12:59937) at nO (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\node_modules\next\dist\compiled\next-server\app-page.runtime.prod.js:12:62795) at nI (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\node_modules\next\dist\compiled\next-server\app-page.runtime.prod.js:12:65445) at nT (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\node_modules\next\dist\compiled\next-server\app-page.runtime.prod.js:12:57207) Generating static pages (6/7) [ ] Error occurred prerendering page "/". Read more: https://nextjs.org/docs/messages/prerender-error Error at l (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\.next\server\app\page.js:10:343) at C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\.next\server\app\page.js:19:1632 at C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\.next\server\app\page.js:19:3359 at k (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\.next\server\app\page.js:19:3362) at nT (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\node_modules\next\dist\compiled\next-server\app-page.runtime.prod.js:12:46138) at nT (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\node_modules\next\dist\compiled\next-server\app-page.runtime.prod.js:12:59937) at nO (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\node_modules\next\dist\compiled\next-server\app-page.runtime.prod.js:12:62795) at nI (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\node_modules\next\dist\compiled\next-server\app-page.runtime.prod.js:12:65445) at nT (C:\Users\batin\OneDrive\Bureaublad\server-live\vercel\node_modules\next\dist\compiled\next-server\app-page.runtime.prod.js:12:57207) ✓ Generating static pages (7/7) > Export encountered errors on following paths: /page: /
相关代码
crimeData.tsx
'use client' import {Crimes} from "@/types/db/Crimes"; import {WithId} from "mongodb"; import React, {ChangeEvent, useState} from "react"; import {useNavigate} from 'react-router-dom'; interface FormProps { data: WithId<Crimes>[]; } const Data: React.FC<FormProps> = ({data}) => { const navigate = useNavigate(); const [municipality, setMunicipality] = useState<Crimes | null>(null); const [error, setError] = useState(false) const handleDropdown = (selectedOption: ChangeEvent<HTMLSelectElement>) => { const select = selectedOption.target.value const selectData = data.find((crime) => crime._id.toString() === select) if (selectData) { setMunicipality(selectData) } } const reload = () => { window.location.reload(); } const handleButton = () => { try { if (municipality !== null) { navigate('crimes', {state: {municipality: municipality}}); reload(); } else { console.error(setError) } } catch (error) { console.error(setError) } } return ( <main className={"flex flex-row"}> <div className={"dropdown flex flex-col items-start-4"}> <h2 className={'ml-5 font-bold'}>Crimineel dataset</h2> <select className={"other-drop p-4"} onChange={handleDropdown}> {data.map((crimes) => ( <option key={crimes._id.toString()} value={crimes._id.toString()}> {crimes.Title} </option> ))} </select> <button className={"btn btn-other"} onClick={handleButton}> Resultaat </button> </div> </main> ) } export default Data
page.tsx
import {getNeighborhoods} from '@/utlis/mongodb/neighborhood'; // import Data from './data' import CrimeData from './crimeData' import { getCrimes } from '@/utlis/mongodb/crimes'; import { getRiskscore } from '@/utlis/mongodb/riskscore'; // import User from './user' export default async function Home() { try { const neighborhoodData = await getNeighborhoods() const data = await neighborhoodData.toArray() const crimesData = await getCrimes() const crimesD = await crimesData.toArray() const userData = await getRiskscore() const user = await userData.toArray() return ( <main className="flex min-h-screen flex-col items-center justify-between p-24 md:container md:mx-auto"> <div className="homepage-div flex"> <div className="home p-4"> <h1 className={"text-2xl font-bold mb-2"}>Politieoverlast</h1> {/* eslint-disable-next-line react/no-unescaped-entities */} <p className={"text-gray-700"}>Welkom bij "politieoverlast," jouw online bron voor het verkennen van maatschappelijke uitdagingen en het bevorderen van bewustwording. Onze missie is om een dieper begrip te creëren van problemen die onze samenleving beïnvloeden, en we beginnen met twee {/* eslint-disable-next-line react/no-unescaped-entities */} cruciale datasets: alcoholoverlast en het mysterieuze "xxx."</p> <br/> <p className={"text-gray-700"}><b>Overlastscores voor Alcoholoverlast:</b> Dit is een probleem dat vele gemeenschappen wereldwijd treft. Het overmatige gebruik van alcohol kan leiden tot ernstige {/* eslint-disable-next-line react/no-unescaped-entities */} gevolgen, waaronder gezondheidsproblemen, sociale conflicten en veiligheidsrisico's. Op {/* eslint-disable-next-line react/no-unescaped-entities */} "politieoverlast" hebben we overlastscores verzameld en geanalyseerd om te laten zien welke gemeenten het meest getroffen zijn door alcoholgerelateerde problemen. We presenteren deze scores op een schaal van 1 tot 100 om de ernst van de situatie duidelijk te maken.</p> <div className={"home-btns flex flex-row "}> {/*<Data data={data}/>*/} <CrimeData data={crimesD}/> </div> <div> <h2>Gebruiker update</h2> {/*<User data={user} />*/} </div> </div> </div> </main> ) } catch (error) { console.error('Error fetching data:', error); throw error; } }
问题原因及解决方法
核心原因
Next.js App Router 自带完整路由系统,与react-router-dom存在底层冲突。预渲染阶段在Node.js环境执行,react-router-dom的useNavigate等钩子依赖浏览器路由上下文,导致执行报错。此外代码还存在两个冗余问题:
- 跳转后立即调用
window.location.reload(),完全抵消客户端路由作用 console.error(setError)是错误用法,未正确设置错误状态
解决步骤
1. 移除react-router-dom,改用Next.js原生路由
卸载react-router-dom:
npm uninstall react-router-dom
修改crimeData.tsx,替换路由逻辑:
'use client' import {Crimes} from "@/types/db/Crimes"; import {WithId} from "mongodb"; import React, {ChangeEvent, useState} from "react"; import {useRouter} from 'next/navigation'; interface FormProps { data: WithId<Crimes>[]; } const Data: React.FC<FormProps> = ({data}) => { const router = useRouter(); const [municipality, setMunicipality] = useState<Crimes | null>(null); const [error, setError] = useState(false) const handleDropdown = (selectedOption: ChangeEvent<HTMLSelectElement>) => { const select = selectedOption.target.value const selectData = data.find((crime) => crime._id.toString() === select) if (selectData) { setMunicipality(selectData) setError(false); } } const handleButton = () => { if (municipality !== null) { router.push(`/crimes?id=${municipality._id.toString()}`); } else { setError(true); console.error("No municipality selected"); } } return ( <main className={"flex flex-row"}> <div className={"dropdown flex flex-col items-start-4"}> <h2 className={'ml-5 font-bold'}>Crimineel dataset</h2> {error && <p className="text-red-500 ml-5 mt-2">Selecteer een gemeente eerst!</p>} <select className={"other-drop p-4 mt-2"} onChange={handleDropdown}> <option value="">-- Kies een gemeente --</option> {data.map((crimes) => ( <option key={crimes._id.toString()} value={crimes._id.toString()}> {crimes.Title} </option> ))} </select> <button className={"btn btn-other mt-2"} onClick={handleButton}> Resultaat </button> </div> </main> ) } export default Data
2. 处理/crimes页面的数据接收
在app/crimes/page.tsx中通过查询参数获取数据:
import { getCrimes } from '@/utlis/mongodb/crimes'; import { WithId } from 'mongodb'; import { Crimes } from '@/types/db/Crimes'; export default async function CrimesPage({ searchParams }: { searchParams: { id: string } }) { const crimesData = await getCrimes(); const allCrimes = await crimesData.toArray(); const municipality = allCrimes.find(crime => crime._id.toString() === searchParams.id); if (!municipality) { return <div className="p-24">Gemeente niet gevonden!</div>; } return ( <div className="p-24"> <h1 className="text-2xl font-bold mb-4">{municipality.Title}</h1> {/* 渲染你的数据内容 */} </div> ) }
3. 确保预渲染正常执行
如果数据查询依赖浏览器环境,可在page.tsx顶部添加配置禁用静态预渲染:
export const dynamic = "force-dynamic";
内容的提问来源于stack exchange,提问作者B.Simsek
相关产品推荐
相关产品推荐

