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

React Router v6自定义404页面异常显示问题求助

React Router v6 404页面异常显示问题解决

问题场景

想要在访问不存在的页面时显示自定义404页面,添加了<Route path='*' element={<MissingPage />} />路由,但除主页外,所有页面底部都会显示该404页面,尝试旧版本的exact属性无效。

依赖版本:

"dependencies": {
  "@craco/craco": "^6.4.3",
  "@emotion/react": "^11.9.0",
  "react": "^18.1.0",
  "react-dom": "^18.1.0"
},
"devDependencies": {
  "react-router-dom": "^6.3.0"
}

原主路由结构:

return (
    <ThemeProvider theme={theme}>
        <SharedContextProvider>
            <div className='main'>
                <BrowserRouter>
                    <SharedDataManagement>
                        <Fragment>
                            <AuthRoutes />
                            <DashboardRoutes />
                            <SubscriptionsContextProvider>
                                <SubscriptionsRoutes />
                            </SubscriptionsContextProvider>
                            <PaymentRoutes />
                            <CommitmentRoutes />
                            <CoursesRoutes />
                            <ContactUsRoutes />
                            <ErrorsRoutes />
                            <Routes>
                                <Route path='/' element={<HomePageComponent />} />
                                <Route path='*' element={<MissingPage />} />
                            </Routes>
                        </Fragment>
                    </SharedDataManagement>
                </BrowserRouter>
            </div>
        </SharedContextProvider>
    </ThemeProvider>
)

子路由示例(PaymentRoutes):

export function PaymentRoutes() {
    return (
        <PaymentContextProvider>
            <Routes>
                <Route path='/payment' element={<PaymentPage />} />
                <Route path='/payment/success' element={<SubscriptionPage />} />
            </Routes>
        </PaymentContextProvider>
    )
}

子路由示例(CommitmentRoutes):

export function CommitmentRoutes() {
    return (
        <Routes>
            <Route path='/privacy-policy' element={<PrivacyPolicyPage />} />
            <Route path='/terms-and-conditions' element={<TermsAndConditionsPage />} />
            <Route path='/cookie' element={<CookiePage />} />
        </Routes>
    )
}

问题原因

React Router v6中,每个<Routes>组件会独立进行路由匹配,只要当前路径符合组件内的路由规则,就会渲染对应的元素。你现在的代码里存在多个独立的<Routes>(主路由的<Routes>、PaymentRoutes里的<Routes>、CommitmentRoutes里的<Routes>等):

  • 当访问/payment时,PaymentRoutes里的<Routes>匹配到/payment并渲染PaymentPage;
  • 同时主路由的<Routes>里的path='*'会匹配所有非/的路径,因此也会渲染MissingPage;
  • 两个组件同时渲染,导致404页面出现在正常页面底部。

另外,React Router v6已经移除了exact属性,所有路由默认都是精确匹配(嵌套路由除外),所以exact无效是正常的。

解决方案

将所有路由统一到同一个<Routes>组件中,确保只有一个路由匹配上下文,并且把path='*'的404路由放在最后,这样只有当没有其他路由匹配时才会触发它。

修改步骤

  1. 改造所有子路由组件,移除内部的<Routes>,直接返回<Route>元素(可以用<>包裹);
  2. 在主路由的<Routes>中,引入所有子路由的<Route>,并将404路由放在最后。

修改后的代码示例

改造后的PaymentRoutes:

export function PaymentRoutes() {
    return (
        <PaymentContextProvider>
            <>
                <Route path='/payment' element={<PaymentPage />} />
                <Route path='/payment/success' element={<SubscriptionPage />} />
            </>
        </PaymentContextProvider>
    )
}

改造后的CommitmentRoutes:

export function CommitmentRoutes() {
    return (
        <>
            <Route path='/privacy-policy' element={<PrivacyPolicyPage />} />
            <Route path='/terms-and-conditions' element={<TermsAndConditionsPage />} />
            <Route path='/cookie' element={<CookiePage />} />
        </>
    )
}

改造后的主路由结构:

return (
    <ThemeProvider theme={theme}>
        <SharedContextProvider>
            <div className='main'>
                <BrowserRouter>
                    <SharedDataManagement>
                        <Routes>
                            {/* 主页路由 */}
                            <Route path='/' element={<HomePageComponent />} />
                            
                            {/* 引入各子路由 */}
                            <AuthRoutes />
                            <DashboardRoutes />
                            
                            {/* 需要上下文包裹的子路由,用嵌套路由处理 */}
                            <Route element={<SubscriptionsContextProvider><Outlet /></SubscriptionsContextProvider>}>
                                <SubscriptionsRoutes />
                            </Route>
                            
                            <PaymentRoutes />
                            <CommitmentRoutes />
                            <CoursesRoutes />
                            <ContactUsRoutes />
                            <ErrorsRoutes />
                            
                            {/* 404路由必须放在最后 */}
                            <Route path='*' element={<MissingPage />} />
                        </Routes>
                    </SharedDataManagement>
                </BrowserRouter>
            </div>
        </SharedContextProvider>
    </ThemeProvider>
)

如果子路由组件需要上下文包裹(比如SubscriptionsRoutes需要SubscriptionsContextProvider),可以用嵌套路由的方式:通过element属性设置上下文组件,内部用<Outlet />渲染子路由内容,这样子路由的所有页面都会继承该上下文。

这样修改后,只有当没有任何路由匹配当前路径时,才会渲染MissingPage,正常页面不会再显示404内容。

内容的提问来源于stack exchange,提问作者Dmitr Zar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 08:15:43