You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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等钩子依赖浏览器路由上下文,导致执行报错。此外代码还存在两个冗余问题:

  1. 跳转后立即调用window.location.reload(),完全抵消客户端路由作用
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 07:35:54