Skip to content

并行路由

介绍

并行路由(Parallel Routes)是 Next.js 13 引入的一项功能,允许在同一页面中渲染多个独立的路由区域。

并行路由的好处:

  • 组合式 UI 与可复用性:允许在同一页面同时渲染多个独立区域(slot),例如侧栏、通知面板和主内容区,便于把不同功能模块化和复用。
  • 感知性能提升:并行区域可以独立加载和流式渲染,用户更快看到关键内容,改善首屏体验(First Contentful Paint)。
  • 独立的数据与缓存策略:每个并行路由可以有自己的数据获取与缓存策略,减少不必要的重渲染与数据请求。
  • 更细粒度的代码拆分:只在需要时加载对应并行路由的 bundle,降低初始包体积。
  • 功能隔离与团队并行开发:不同团队或功能可以在各自并行路由中独立开发、灰度与回滚,降低耦合。
  • 布局复用且减少重渲染:共享 layout 保持不变,只替换或并行渲染子区域,避免整页重构。

基本使用

要使用并行路由,您需要在 app 目录下创建一个新的文件夹,并使用 @ 符号来定义并行路由。例如:

bash
app/
└── dashboard/
    ├── @notifications/
   └── page.tsx
    ├── @revenue/
   └── page.tsx
    ├── @users/
   └── page.tsx
    ├── layout.tsx
    └── page.tsx

layout.tsx 文件:

tsx
export default function DashboardLayout({
  children,
  notifications,
  revenue,
  users,
}: {
  children: React.ReactNode
  notifications: React.ReactNode
  revenue: React.ReactNode
  users: React.ReactNode
}) {
  return (
    <div>
      <h1>Dashboard</h1>
      <div style={{ display: 'flex' }}>
        <div style={{ flex: 1 }}>{children}</div>
        <div style={{ flex: 1 }}>{notifications}</div>
        <div style={{ flex: 1 }}>{revenue}</div>
        <div style={{ flex: 1 }}>{users}</div>
      </div>
    </div>
  )
}

处理不匹配的路由

示例与说明:

如果你把 archive 放在 @notifications/archive/page.tsx 下,这个 archive 是该插槽(slot)内部的路由片段。并行路由的插槽不是默认作为主 URL 路径的一部分,因此直接在浏览器地址栏输入 /dashboard/archive 并不一定会匹配到插槽内的 archive 页面,可能导致 404(或匹配到其他同名的主路由片段)。

为避免刷新或直接访问时出现 404,可以采用以下做法:

  • 在并行路由的 slot 或父级创建 default.tsx 作为默认展示内容(slot 的回退页面)。
  • 如果 archive 应该是一个可直接访问的 URL,请把它放在主路由层级(例如 app/dashboard/archive/page.tsx),或使用拦截路由(Intercepting Routes)将可分享的路径映射为插槽渲染。

下面是一个包含默认路由的示例结构:

bash
app/
└── dashboard/
  ├── @notifications/
   ├── archive/
   └── page.tsx # 插槽内部的嵌套路由(仅作为 slot 内容)
   └── page.tsx
  ├── @revenue/
   ├── default.tsx # 当 slot 没有匹配时的回退内容
   └── page.tsx
  ├── @users/
   ├── default.tsx # 当 slot 没有匹配时的回退内容
   └── page.tsx
  ├── default.tsx # dashboard 主插槽的默认页面
  ├── layout.tsx
  └── page.tsx

要点小结

  • @slotName 文件夹用来声明并行路由的插槽(slot),在对应的 layout.tsx 中会以同名 prop(去掉 @)接收该插槽的渲染内容,例如 @notifications -> notifications prop。
  • 插槽内容默认不会改变主 URL 的路由片段;如果需要可分享的路径或直接访问,请把路由放到主层级或配合拦截路由处理。
  • 使用 default.tsx 为插槽提供回退页面,避免刷新或直接访问时出现 404。
  • 并行路由适用于同时展示多个独立区域,但要关注路由可访问性与 SEO 情况。

条件路由

bash
app/
└── dashboard/
   @login/
   └── page.tsx # 登录路由
    ├── @notifications/
   ├── archive/
   └── page.tsx
   └── page.tsx
    ├── @revenue/
   ├── default.tsx
   └── page.tsx
    ├── @users/
   ├── default.tsx
   └── page.tsx
    ├── default.tsx
    ├── layout.tsx
    └── page.tsx

layout.tsx 中:

tsx
export default function DashboardLayout({
  children,
  notifications,
  revenue,
  users,
  login,
}: {
  children: React.ReactNode
  notifications: React.ReactNode
  revenue: React.ReactNode
  users: React.ReactNode
  login: React.ReactNode
}) {
  const isLoggedIn = false // 模拟登录状态

  return (
    <div>
      <h1>Dashboard</h1>
      {!isLoggedIn ? (
        <div style={{ display: 'flex' }}>
          <div style={{ flex: 1 }}>{children}</div>
          <div style={{ flex: 1 }}>{notifications}</div>
          <div style={{ flex: 1 }}>{revenue}</div>
          <div style={{ flex: 1 }}>{users}</div>
        </div>
      ) : (
        login
      )}
    </div>
  )
}

基于 MIT 许可发布