React 嵌套路由与布局

前置:路由

目标:用嵌套 Route + Outlet 做布局(顶栏/侧栏只写一次),并能独立设计多层路由树。

引言

后台常见结构:顶栏 + 侧栏固定,中间内容随 URL 变。

若每个页面都复制一遍壳子,改导航要改 N 处,登录态、面包屑、权限也无处安放。

嵌套路由 解决的正是这件事:父路由渲染布局,子路由填进布局里的 <Outlet />(挖好的洞)。

本篇 demo:Shell 包住「概览 / 设置」;设置里再嵌一层「资料」。

动手

完整代码:react2/13-nested-routes/demo

bash 复制代码
cd react2/13-nested-routes/demo
npm install && npm run dev

点「概览 / 设置 / 资料」,看顶栏一直在,只有内容区换。


1. 先把「URL 树」和「组件树」对上

嵌套路由不是新 API,它只是把两棵树对齐:

text 复制代码
URL                   组件树
/                     Shell → Home
/settings             Shell → Settings
/settings/profile     Shell → Settings → Profile

记住一句话:URL 有几层,组件树就可以有几层;<Outlet /> 是每一层的插槽。

对照 demo 的实际渲染结果:

访问地址 同时挂载的组件 内容区显示
/ Shell → Home 概览
/settings Shell → Settings 设置布局(Outlet 为空)
/settings/profile Shell → Settings → Profile 资料

Shell 和 Settings 都是「布局组件」,它们本身不直接对应某个业务结果,只负责壳和插槽。


2. 父布局 + Outlet

tsx 复制代码
function Shell() {
  return (
    <main>
      <nav>
        <Link to="/">概览</Link>
        <Link to="/settings">设置</Link>
        <Link to="/settings/profile">资料</Link>
      </nav>
      <Outlet />
    </main>
  )
}

Shell 自己不对应最终「业务页」,只提供壳;<Outlet /> 位置渲染匹配到的子路由。

几个容易忽略的点:

  • Outlet 不是「可选装饰」,没有它子路由就无家可归,页面会只剩布局。
  • 一个布局里可以放多个 Outlet,但通常一个就够;多出口属于进阶玩法。
  • 布局组件里可以正常用 hooks(useLocation、useNavigate),它仍然是普通组件。

3. 路由表怎么嵌

tsx 复制代码
<Routes>
  <Route element={<Shell />}>
    <Route index element={<Home />} />
    <Route path="settings" element={<Settings />}>
      <Route path="profile" element={<Profile />} />
    </Route>
  </Route>
</Routes>
写法 含义
无 path 的父 Route 只提供 layout(本 demo 的 Shell)
index 父路径本身,如 / → Home
path="settings" 相对父路径 → /settings
再嵌 profile → /settings/profile;Settings 里也要有 <Outlet />
tsx 复制代码
function Settings() {
  return (
    <section>
      <h2>设置布局</h2>
      <Link to="/settings/profile">去资料子页</Link>
      <Outlet />
    </section>
  )
}

访问 /settings/profile 时:Shell → Settings → Profile 三层同时挂着。

小提醒:index 只能出现在「有父级 path 或布局」的位置;它表示「父路径的默认子页」,不是单独的 URL 段。


4. 相对路径 vs 绝对路径

子路由的 path 默认是相对父路径的,这是嵌套路由能层层拼接的关键。

子路由写法 实际匹配
<Route path="settings"> 挂在 Shell 下 /settings
<Route path="profile"> 挂在 settings 下 /settings/profile
<Route path="/settings/profile"> 挂在 Shell 下 绝对路径,直接匹配 /settings/profile

新手建议:

  • 布局嵌套用相对路径,层级关系一眼能看懂。
  • 只有确实想「跳出父级、从根开始」时才用绝对路径。
  • 写绝对路径却挂在错误的父级下,容易出现「URL 对、页面结构不对」的诡异现象。

5. 导航高亮与 404

真实后台还会关心两件事:当前菜单高亮、未知地址兜底。

高亮用 NavLink,它会根据匹配状态给 className:

tsx 复制代码
import { NavLink } from 'react-router-dom'

<NavLink
  to="/settings"
  className={({ isActive }) => (isActive ? 'active' : undefined)}
>
  设置
</NavLink>

404 兜底通常放在最外层,且不要塞进业务布局里(否则 404 页面也会带后台侧栏):

tsx 复制代码
<Routes>
  <Route element={<Shell />}>
    <Route index element={<Home />} />
    <Route path="settings" element={<Settings />}>
      <Route path="profile" element={<Profile />} />
    </Route>
  </Route>
  <Route path="*" element={<p>页面不存在</p>} />
</Routes>

6. 布局给子路由传数据(进阶)

有时布局里有筛选条件、主题、当前用户,子页需要读。可以用 useOutletContext:

tsx 复制代码
import { useState } from 'react'
import { Outlet, useOutletContext } from 'react-router-dom'

function Shell() {
  const [theme, setTheme] = useState<'light' | 'dark'>('light')
  return (
    <>
      <button onClick={() => setTheme((t) => (t === 'light' ? 'dark' : 'light'))}>
        切换主题
      </button>
      <Outlet context={{ theme }} />
    </>
  )
}

function Profile() {
  const { theme } = useOutletContext<{ theme: string }>()
  return <p>当前主题:{theme}</p>
}

它不是全局状态,只沿「布局 → 子路由」这条线传值;跨业务的共享仍应交给 Context / Zustand。


7. 对照表

概念 干什么 demo
布局路由 公共壳只写一次 Shell
Outlet 子路由出口 Shell / Settings 各一处
index 父 URL 默认页 / → Home
相对 path 拼出层级 URL settings / profile
通配 * 404 兜底 可加在最外层
NavLink 当前导航高亮 可替换 Link
useOutletContext 布局向子路由传值 进阶示例

8. 常见坑

做法 问题
布局里忘了 <Outlet /> 子路由匹配了但空白
子路由写成绝对 /settings/profile 却挂错层级 嵌套关系乱;新手先用相对 path
每个页面再包一遍同一导航 失去嵌套布局意义
index 和 path="" 混用 语义不清,容易出现重复匹配
把 404 放进后台布局 404 页也显示侧栏,体验奇怪
和「鉴权守卫」混淆 守卫也是布局路由套路,见 19 篇

9. 调试清单

页面空白或层级不对时,按顺序排查:

  1. 浏览器地址栏 URL 是否与路由表预期一致?
  2. 每一层布局组件里是否都有 <Outlet />?
  3. 子路由 path 是相对还是绝对?是否拼错层级?
  4. Routes 外层是否有 BrowserRouter?
  5. 打开 React DevTools,看组件树里 Shell / Settings / Profile 是否按预期嵌套。

demo 在练什么

  1. 一层布局 Shell + Outlet
  2. 设置下再嵌 profile
  3. 用 Link 在层级间跳转,观察 URL 与 UI

自己改一改:

  • 在 Shell 旁加 /about;
  • 给 settings 加 index 默认页;
  • 把 Link 换成 NavLink,给当前菜单加高亮样式;
  • 在最外层加 path="*" 的 404 页。

下一篇

表单:React Hook Form + Zod

相关推荐
htzyl2061 小时前
前端阶梯——第四十三章、实战二:待办清单To-Do
前端·javascript·html
摹客2 小时前
【3D设计】界面设计中的3D元素:应用场景+5款工具横评(含Three.js)
前端
Hilaku2 小时前
CORS 到底在保护谁?90% 的前端理解错了跨域的本质
前端·javascript·程序员
wno7043 小时前
node.js中使用jquery
前端·node.js·jquery
阿琳a_3 小时前
b-map-viewer:面向 Vue 3 的地图可视化 SDK,从接入到展示再到交互分析
前端·javascript·vue.js·gis·数据可视化·地图
10年前端老司机3 小时前
Agent 商业化困局:热闹的发布会,冷清的付费客户
前端·后端·agent
钱栈up3 小时前
热榜上手|HyperFrames:写HTML出MP4
前端·html
Sailing3 小时前
🚀🚀【封闭结束8】Agent RAG:从零搭建一个可用知识库
前端·后端·agent