主题
并行路由
介绍
并行路由(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.tsxlayout.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->notificationsprop。- 插槽内容默认不会改变主 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>
)
}