并行路由
并行路由允许你在同一布局中同时或有条件地渲染一个或多个页面。它们对于应用程序中高度动态的部分非常有用,例如仪表盘和社交网站上的信息流。
例如,考虑一个仪表盘,你可以使用并行路由同时渲染 "team" 和 "analytics" 页面:
并行路由是通过命名 插槽 创建的。插槽使用 @folder
约定定义。例如,以下文件结构定义了两个插槽:@analytics
和 @team
:
插槽作为 props 传递给共享的父级布局。对于上面的例子,app/layout.js
中的组件现在接受 @analytics
和 @team
插槽 props,并可以与 children
prop 一起并行渲染它们:
然而,插槽 不是 路由段,不会影响 URL 结构。例如,对于 /@analytics/views
,URL 将是 /views
,因为 @analytics
是一个插槽。
值得注意的是:
children
prop 是一个隐式插槽,不需要映射到文件夹。这意味着 app/page.js
等同于 app/@children/page.js
。
默认情况下,Next.js 会跟踪每个插槽的活动 状态 (或子页面)。但是,插槽内渲染的内容将取决于导航类型:
- 软导航:在客户端导航期间,Next.js 将执行部分渲染,改变插槽内的子页面,同时保持其他插槽的活动子页面,即使它们不匹配当前 URL。
- 硬导航:在完整页面加载 (浏览器刷新) 后,Next.js 无法确定不匹配当前 URL 的插槽的活动状态。相反,它将为不匹配的插槽渲染
default.js
文件,如果 default.js
不存在则渲染 404
。
值得注意的是:
- 不匹配路由的
404
有助于确保你不会意外地在不适当的页面上渲染并行路由。
你可以定义一个 default.js
文件,作为初始加载或完整页面重新加载时未匹配插槽的回退渲染。
考虑以下文件夹结构。@team
插槽有一个 /settings
页面,但 @analytics
没有。
当导航到 /settings
时,@team
插槽将渲染 /settings
页面,同时保持 @analytics
插槽的当前活动页面。
在刷新时,Next.js 将为 @analytics
渲染一个 default.js
。如果 default.js
不存在,则渲染 404
。
此外,由于 children
是一个隐式插槽,你还需要创建一个 default.js
文件来为 children
渲染回退,以防 Next.js 无法恢复父页面的活动状态。
useSelectedLayoutSegment
和 useSelectedLayoutSegments
都接受一个 parallelRoutesKey
参数,允许你读取插槽内的活动路由段。
当用户导航到 app/@auth/login
(或 URL 栏中的 /login
) 时,loginSegment
将等于字符串 "login"
。
你可以使用并行路由基于某些条件 (如用户角色) 有条件地渲染路由。例如,为 /admin
或 /user
角色渲染不同的仪表盘页面:
你可以在插槽内添加一个 layout
,允许用户独立导航该插槽。这对于创建标签很有用。
例如,@analytics
插槽有两个子页面:/page-views
和 /visitors
。
在 @analytics
内创建一个 layout
文件,在两个页面之间共享标签:
并行路由可以与拦截路由一起使用,以创建支持深度链接的模态框。这允许你解决构建模态框时的常见挑战,例如:
- 使模态框内容可以通过 URL 共享。
- 在页面刷新时 保留上下文,而不是关闭模态框。
- 在向后导航时 关闭模态框,而不是回到上一个路由。
- 在向前导航时 重新打开模态框。
考虑以下 UI 模式,用户可以从布局中使用客户端导航打开登录模态框,或访问单独的 /login
页面:
要实现这种模式,首先创建一个 /login
路由来渲染你的 主要 登录页面。
然后,在 @auth
插槽内添加一个 default.js
文件,返回 null
。这可以确保当模态框不活动时不会被渲染。
在你的 @auth
插槽内,通过更新 /(.)login
文件夹来拦截 /login
路由。将 <Modal>
组件及其子组件导入到 /(.)login/page.tsx
文件中:
值得注意的是:
- 用于拦截路由的约定 (例如
(.)
) 取决于你的文件系统结构。参见拦截路由约定。
- 通过将
<Modal>
功能与模态框内容 (<Login>
) 分开,你可以确保模态框内的任何内容 (例如 表单) 都是服务器组件。有关更多信息,请参阅交错客户端和服务器组件。
现在,你可以利用 Next.js 路由器来打开和关闭模态框。这确保了在模态框打开时 URL 被正确更新,以及在向后和向前导航时的行为。
要打开模态框,将 @auth
插槽作为 prop 传递给父级布局,并将其与 children
prop 一起渲染。
当用户点击 <Link>
时,模态框将打开,而不是导航到 /login
页面。但是,在刷新或初始加载时,导航到 /login
会将用户带到主登录页面。
你可以通过调用 router.back()
或使用 Link
组件来关闭模态框。
当使用 Link
组件导航到不应再渲染 @auth
插槽的页面时,我们需要确保并行路由匹配到一个返回 null
的组件。例如,当导航回根页面时,我们创建一个 @auth/page.tsx
组件:
或者如果导航到任何其他页面 (如 /foo
、/foo/bar
等),你可以使用一个捕获所有的插槽:
值得注意的是:
- 我们在
@auth
插槽中使用捕获所有路由来关闭模态框,是因为活动状态和导航中描述的行为。由于客户端导航到不再匹配插槽的路由时会保持可见,我们需要将插槽匹配到一个返回 null
的路由来关闭模态框。
- 其他示例可能包括在图库中打开照片模态框,同时也有一个专门的
/photo/[id]
页面,或者在侧边模态框中打开购物车。
- 查看一个示例,了解使用拦截和并行路由的模态框。
并行路由可以独立流式传输,允许你为每个路由定义独立的错误和加载状态:
查看加载 UI和错误处理文档以获取更多信息。