This repository has been archived on 2026-05-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
obsidian/金山办公作业/Week06/Outlet.md
T

3.9 KiB
Raw Blame History

tags, create time
tags create time
frontend
react
react-router
routing
nested-routes
2026-04-25 15:30

Outlet:嵌套路由的出口 / 占位符

概述

Outlet 是 React Router 中用于"嵌套路由占位"的组件,负责在父组件布局中预留一个位置,由子路由匹配到的组件来渲染。

正文

为什么要用 Outlet

假设有这样的路由结构:

  • /dashboard
  • /courses
  • /students

它们都共享同一个外层布局——左侧导航栏、顶部标题栏、主内容区域。如果不使用 Outlet,每个页面组件都要重复写一遍布局结构。

有了 Outlet,可以把公共布局抽到一个父路由组件中,子页面内容自动渲染到 Outlet 位置,不需要重复代码。

💡 想一想:如果每个子页面都自己写侧边栏和顶栏,当侧边栏需要修改时,需要改几个文件?用了 Outlet 后又需要改几个?

路由结构对比

graph TB
    subgraph "不使用 Outlet"
        A1[LoginPage] --> B1[浏览器]
        A2[DashboardPage] --> B1
        A3[CoursesPage] --> B1
        A4[StudentsPage] --> B1
    end

    subgraph "使用 Outlet"
        Layout[Layout 父组件<br/>header + aside + Outlet] --> B2[浏览器]
        subgraph "Layout 内部"
            H[<header>]
            S[<aside>]
            O[<Outlet />]
            H --> O
            S --> O
        end
        O --> C1[DashboardPage]
        O --> C2[CoursesPage]
        O --> C3[StudentsPage]
    end

左边:每个页面独立渲染,布局代码重复。右边:父组件统一管理布局,子页面只关心自己的内容。

布局组件实现

import { Outlet } from 'react-router-dom'

function Layout() {
  return (
    <div className="app-layout">
      <header>顶部栏</header>          {/* 固定不变 */}
      <aside>侧边栏</aside>            {/* 固定不变 */}
      <main>
        <Outlet />                     {/* 子路由内容渲染到这里 */}
      </main>
    </div>
  )
}

解读:Layout 组件中,<header> 和 <aside> 是固定结构,始终显示;<Outlet /> 是一个"占位符",React Router 会自动把当前路径匹配到的子组件渲染到它的位置。

路由声明方式

JSX 声明式写法:

<Route element={<Layout />}>           {/* 父路由:负责布局 */}
  <Route path="/dashboard" element={<DashboardPage />} />
  <Route path="/courses"   element={<CoursesPage />} />
  <Route path="/students"  element={<StudentsPage />} />
</Route>

配置文件写法:

const router = createBrowserRouter([
  {
    path: '/',
    element: <Layout />,               {/* 父路由组件 */}
    children: [                        {/* 子路由列表 */}
      { path: 'dashboard', element: <DashboardPage /> },
      { path: 'courses',   element: <CoursesPage /> },
      { path: 'students',  element: <StudentsPage /> },
    ],
  },
])

两种方式等价,选择哪种取决于项目规模和个人偏好。

Routes vs Outlet

特性 <Routes> <Outlet />
职责 匹配路径,决定显示哪个组件 在父组件中预留子组件渲染位置
在哪用 任意需要路由判断的地方 只在父路由组件内部
类比 调度中心 出口 / 窗口
// Routes:路径 → 组件 的映射表
<Routes>
  <Route path="/courses" element={<CoursesPage />} />
</Routes>

// Outlet:父组件留给子组件的"位置"
function Layout() {
  return (
    <div>
      <Header />
      <Outlet />          {/* 子组件会出现在这里 */}
    </div>
  )
}

💡 想一想:如果父路由组件里没有放 <Outlet />,子路由对应的页面还能显示出来吗?(不能,子组件找不到挂载点,不会被渲染到页面上。)

关联笔记

  • 路由原理 - BrowserRouter、Routes、Route 等核心路由组件