人人都会AI编程

12.1 路由基础配置与嵌套路由

更新时间:2026-07-11

在单页应用(SPA)中,页面切换不会触发完整的浏览器刷新,而是通过 JavaScript 动态替换页面内容。React Router v6 是目前 React 生态里最主流的路由解决方案,提供了声明式、可组合的 API,并且完整支持嵌套路由、相对路径、数据加载等现代特性。

安装与起步

npm install react-router-dom

核心组件全部从 react-router-dom 导入:

import { BrowserRouter, Routes, Route, Link, Outlet } from 'react-router-dom';

最简路由配置

任何一个 React Router 应用都需要一个路由器组件包裹整个应用。BrowserRouter 是最常用的路由器,它使用 HTML5 的 history API 来保持 UI 和 URL 的同步。

import { BrowserRouter, Routes, Route } from 'react-router-dom';

function Home() { return <h2>首页</h2>; }
function About() { return <h2>关于我们</h2>; }
function NotFound() { return <h2>404 页面不存在</h2>; }

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
}

要点说明:

  • BrowserRouter 包裹在应用最外层,整个应用内部都可以使用路由。
  • Routes 用来定义路由规则,它会遍历内部的 Route 并返回第一个匹配的组件。
  • Route 通过 path 指定 URL 路径(区分大小写),通过 element 指定渲染的组件。
  • path="*" 表示匹配所有未被上面规则匹配的路径,通常用于 404 页面。

使用 Link 导航

不要使用 <a> 标签跳转,因为它会触发浏览器整页刷新。React Router 提供了 Link 组件,它会渲染一个 <a> 标签,但通过 history API 实现无刷新跳转。

import { Link } from 'react-router-dom';

function NavBar() {
  return (
    <nav>
      <Link to="/">首页</Link>
      <Link to="/about">关于</Link>
    </nav>
  );
}

还可以使用 NavLink,它会在匹配到当前路径时自动添加 active 类名,方便高亮当前导航。

嵌套路由

嵌套路由允许在页面内定义子路由,适用于布局嵌套场景,比如后台管理系统的侧边栏布局、多级菜单等。v6 的嵌套路由不需要再在子组件中写 <Routes><Route>,而是直接在父路由中声明子 Route,并通过 <Outlet> 指定子路由的渲染位置。

示例:包含仪表盘和设置子页面的用户管理

// 布局组件
function UserLayout() {
  return (
    <div>
      <h2>用户管理</h2>
      <nav>
        <Link to="dashboard">仪表盘</Link>
        <Link to="settings">设置</Link>
      </nav>
      {/* 子路由内容在这里渲染 */}
      <Outlet />
    </div>
  );
}

// 子页面组件
function Dashboard() { return <p>仪表盘内容</p>; }
function Settings() { return <p>设置页面</p>; }

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        {/* 嵌套路由 */}
        <Route path="users" element={<UserLayout />}>
          <Route index element={<Dashboard />} />      {/* 默认子路由 */}
          <Route path="dashboard" element={<Dashboard />} />
          <Route path="settings" element={<Settings />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

说明:

  • Route path="users" 是父路由,它的 elementUserLayout,里面用 <Outlet /> 作为占位符。
  • Routepath 是相对于父路径的,即 /users/dashboard/users/settings
  • index 路由:当用户访问 /users 时,默认显示 Dashboard 组件,相当于子路由的“首页”。没有 index 时,访问父路径只会渲染 UserLayoutOutlet 位置为空。

嵌套路由的另一种书写方式:集中配置

如果你习惯将所有路由集中在一个地方,也可以写成无组件嵌套的形式(将子路由直接放在父路由内部)。上面的例子已经是集中式,实际项目中通常将所有路由抽取到一个配置文件或一个专用组件中。

相对链接

在嵌套路由中使用 Link 时,推荐使用相对路径(不以 / 开头),这样当父路由变动时,子导航不必修改:

// 在 UserLayout 中
<Link to="dashboard">仪表盘</Link>    // 解析为 /users/dashboard
<Link to="settings">设置</Link>       // 解析为 /users/settings

如果用 <Link to="/users/dashboard"> 也是可以的,但失去了灵活性。

路由匹配与精确匹配

React Router v6 默认采用精确前缀匹配:即路径 /users 会匹配 /users/users/dashboard 等所有以 /users 开头的路径,但不会匹配 /user。在嵌套路由中,父路由匹配后,会继续在子路由中查找最精确的匹配项。

编程式导航

除了 Link,还可以使用 useNavigate 钩子进行编程式跳转:

import { useNavigate } from 'react-router-dom';

function SomeComponent() {
  const navigate = useNavigate();
  return (
    <button onClick={() => navigate('/about')}>跳转到关于</button>
  );
}

注意事项

  • 路由器选择BrowserRouter 需要服务端配置支持(将路径重定向到 index.html),否则刷新会出现 404。如果服务端无法配置,可以改用 HashRouter(URL 中使用 # 符号)。
  • 路由顺序:v6 使用最佳匹配而非顺序匹配,所以不必将精确路由放在前面,但如果有多个匹配(例如 /users/:id/users/new),推荐将具体路径放在前面清晰表达意图。
  • Outlet:必须存在,否则子路由内容不会显示。通常父组件就是一个布局组件,专门用来包裹侧边栏、导航栏等公共部分。
  • 路径命名:路径变量使用冒号前缀,如 :userId,通过 useParams 获取。

掌握了这些基础,你就能搭建绝大多数应用的路由骨架了。后续还会涉及动态路由、路由守卫、数据路由等进阶特性,但都是在这些基础上叠加的更高层抽象。