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

react-router-dom v6路由匹配失败:嵌套路由迁移后无法正常工作

React Router v6 嵌套路由迁移问题:"No routes match location" 错误

迁移至react-router-dom v6后,原v5中正常运行的组件嵌套路由无法工作,始终提示"No routes match location"。希望在Layout组件中配置路由,触发时加载内部路由,但未成功,此前在v5中使用Switch和BrowserRouter一切正常,无法定位问题。

原始代码

App.js

import React from "react";
import RootRouters from "./components/routers/RootRouters";
import { BrowserRouter as Router } from "react-router-dom";
import "./App.css";

function App() {
    return (
        <Router>
            <div className="App">
                <RootRouters />
            </div>
        </Router>
    );
}

export default App;

RootRouters.js

import React from "react";
import { Route, Routes } from "react-router-dom";
import Login from "../auth-page/login";
import Home from "../home/home";
import SignUp from "../auth-page/sign-up";
import AdminLogin from "../../pages/admin/Login";
import Layout from "../../components/admin/layout/Layout";

const RootRouters = () => {
    return (
        <Routes>
            <Route path="/home" element={<Home />} />
            <Route path="/login" element={<Login />} />
            {/* <Route path="/" element={<Home />} /> */}
            <Route path="/register" element={<SignUp />} />
            <Route path="/admin/login" element={<AdminLogin />} />
            <Route element={<Layout />} />
        </Routes>
    );
};

export default RootRouters;

Layout.js

import React, { useEffect } from "react";
import "./layout.css";
import Sidebar from "../sidebar/Sidebar";
import TopNav from "../topnav/TopNav";
import AdminRoutes from "../../routers/AdminRouters";
import { BrowserRouter, Route } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import ThemeAction from "../../../redux/actions/ThemeAction";

const Layout = () => {
    const themeReducer = useSelector((state) => state.ThemeReducer);

    const dispatch = useDispatch();

    useEffect(() => {
        const themeClass = localStorage.getItem("themeMode", "theme-mode-light");

        const colorClass = localStorage.getItem("colorMode", "theme-mode-light");

        dispatch(ThemeAction.setMode(themeClass));

        dispatch(ThemeAction.setColor(colorClass));
    }, [dispatch]);

    return (
        <Route
            render={(props) => (
                <div className={`layout ${themeReducer.mode} ${themeReducer.color}`}>
                    <Sidebar {...props} />
                    <div className="layout__content">
                        <TopNav />
                        <div className="layout__content-main">
                            <AdminRoutes />
                        </div>
                    </div>
                </div>
            )}
        />
    );
};

export default Layout;

AdminRoutes.js

import React from "react";
import { Route, Routes } from "react-router-dom";
import Dashboard from "../../pages/admin/Dashboard";
import Customers from "../../pages/admin/Customers";
import Products from "../../pages/admin/Products";
import NewDocument from "../../pages/admin/document/NewDocument";
import DetailDocument from "../../pages/admin/document/DetailDocument";
import EditDocument from "../../pages/admin/document/EditDocument";

const AdminRoutes = () => {
    return (
        <Route>
            <Route path="/admin/documents/new" component={NewDocument} />
            <Route path="/admin/documents/detail" component={DetailDocument} />
            <Route path="/admin/documents/update" component={EditDocument} />
            <Route path="/admin/customers" component={Customers} />
            <Route path="/admin/products" component={Products} />
            <Route path="/home" component={Dashboard} />
        </Route>
    );
};

export default AdminRoutes;

问题分析及修正方案

React Router v6 对路由写法做了重大调整,你的代码存在以下核心问题:

  1. 废弃component/render属性:v6中Route不再支持component和render,必须使用element属性传递组件实例。
  2. 嵌套路由写法变更:v6需要通过父路由的children定义子路由,且父路由需设置匹配子路由的路径(比如/admin/*),内部用<Outlet />渲染子路由内容。
  3. Layout组件错误包裹Route:Layout作为布局组件,不需要嵌套Route,直接返回布局结构即可。
  4. RootRouters中Layout路由未设置路径:原代码中Layout的Route没有path,无法匹配任何admin相关路径,导致路由不生效。

修正后的代码

1. RootRouters.js

将Layout路由设置为匹配/admin路径,嵌套定义所有admin子路由:

import React from "react";
import { Route, Routes } from "react-router-dom";
import Login from "../auth-page/login";
import Home from "../home/home";
import SignUp from "../auth-page/sign-up";
import AdminLogin from "../../pages/admin/Login";
import Layout from "../../components/admin/layout/Layout";
import Dashboard from "../../pages/admin/Dashboard";
import Customers from "../../pages/admin/Customers";
import Products from "../../pages/admin/Products";
import NewDocument from "../../pages/admin/document/NewDocument";
import DetailDocument from "../../pages/admin/document/DetailDocument";
import EditDocument from "../../pages/admin/document/EditDocument";

const RootRouters = () => {
    return (
        <Routes>
            <Route path="/home" element={<Home />} />
            <Route path="/login" element={<Login />} />
            <Route path="/register" element={<SignUp />} />
            <Route path="/admin/login" element={<AdminLogin />} />
            {/* 嵌套路由:父路由匹配/admin,子路由用相对路径定义 */}
            <Route path="/admin" element={<Layout />}>
                <Route index element={<Dashboard />} /> {/* 默认加载Dashboard */}
                <Route path="customers" element={<Customers />} />
                <Route path="products" element={<Products />} />
                <Route path="documents/new" element={<NewDocument />} />
                <Route path="documents/detail" element={<DetailDocument />} />
                <Route path="documents/update" element={<EditDocument />} />
            </Route>
        </Routes>
    );
};

export default RootRouters;

2. Layout.js

移除包裹的Route,使用<Outlet />渲染子路由内容:

import React, { useEffect } from "react";
import "./layout.css";
import Sidebar from "../sidebar/Sidebar";
import TopNav from "../topnav/TopNav";
import { Outlet } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import ThemeAction from "../../../redux/actions/ThemeAction";

const Layout = () => {
    const themeReducer = useSelector((state) => state.ThemeReducer);
    const dispatch = useDispatch();

    useEffect(() => {
        const themeClass = localStorage.getItem("themeMode") || "theme-mode-light";
        const colorClass = localStorage.getItem("colorMode") || "theme-mode-light";

        dispatch(ThemeAction.setMode(themeClass));
        dispatch(ThemeAction.setColor(colorClass));
    }, [dispatch]);

    return (
        <div className={`layout ${themeReducer.mode} ${themeReducer.color}`}>
            <Sidebar />
            <div className="layout__content">
                <TopNav />
                <div className="layout__content-main">
                    {/* Outlet专门用于渲染父路由下的子路由内容 */}
                    <Outlet />
                </div>
            </div>
        </div>
    );
};

export default Layout;

3. 保留AdminRoutes的写法(可选)

如果想继续使用AdminRoutes组件,修改如下:

import React from "react";
import { Route, Routes } from "react-router-dom";
import Dashboard from "../../pages/admin/Dashboard";
import Customers from "../../pages/admin/Customers";
import Products from "../../pages/admin/Products";
import NewDocument from "../../pages/admin/document/NewDocument";
import DetailDocument from "../../pages/admin/document/DetailDocument";
import EditDocument from "../../pages/admin/document/EditDocument";

const AdminRoutes = () => {
    return (
        <Routes>
            <Route index element={<Dashboard />} />
            <Route path="customers" element={<Customers />} />
            <Route path="products" element={<Products />} />
            <Route path="documents/new" element={<NewDocument />} />
            <Route path="documents/detail" element={<DetailDocument />} />
            <Route path="documents/update" element={<EditDocument />} />
        </Routes>
    );
};

export default AdminRoutes;

此时RootRouters中Layout的路由改为:

<Route path="/admin/*" element={<Layout />} />

Layout中替换<Outlet />为<AdminRoutes />即可。

关键说明

  • 父路由路径末尾加*表示匹配该路径下的所有子路由(适用于单独抽离子路由组件的场景);直接嵌套子路由时,父路由写/admin,子路由用相对路径即可。
  • <Outlet />是v6中专门用于渲染子路由内容的组件,替代了v5中嵌套Route的写法。
  • 所有路由必须通过element属性传递组件实例,比如element={<Dashboard />},而非component={Dashboard}。

内容的提问来源于stack exchange,提问作者Văn Thuận Nguyễn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 21:10:07