Next.js 在 2016 年发布时的竞争优势之一是其内置的路由系统。它同时支持客户端和服务器端渲染,因此开发人员无需配置像 React Router DOM 这样的第三方路由库。Next.js 的路由器也是基于文件系统的,这意味着应用程序中的路由由文件和文件夹的组织方式决定。这使得它对大多数开发人员更具吸引力。

Vercel 团队一直在通过每个新版本改进路由系统。Next.js 9 引入了 API 路由,让开发人员可以创建处理特定 API 端点的无服务器函数。Next.js 13 引入了 App Router,这是一种新的路由约定,可让您在同一应用程序中渲染客户端和服务器端 React 组件。
App Router 具有许多功能,包括布局、动态路由、嵌套路由以及一组称为并行和相交路由的新路由约定。这些功能可用于创建高级路由模式。
在本文中,我们将探讨什么是平行和相交路线,将它们与现有的路线选项进行比较,了解它们的约定,并演示如何使用它们。
先决条件
预先了解 Next.js 将有助于阅读本文,但如果您对 React 有深入的了解,则不需要了解这些知识
什么是并行路由?
并行路由是 Next.js 中一种新的高级路由约定。根据文档:
“并行路由是一种 Next.js 路由范例,它允许您同时或有条件地在同一布局中渲染一个或多个页面,这些页面可以独立导航。”
换句话说,并行路由允许您在同一视图中渲染多个页面。
并行路由在渲染应用程序的复杂动态部分时最有用,例如在具有多个独立部分或模态的仪表板中。
下图是 Next 文档中的仪表板页面的插图,演示了并行路线的复杂性:

在这种情况下,@team和@analytics路线使用并行路由同时呈现为仪表板布局的部分。
并行路由使用@folder约定来定义,也称为"插槽",本质上是一个以@符号为前缀的文件夹:


为简单起见,我们将在插槽中包含占位符内容,如下所示:
// app/dashboard/@team/page.tsxexport default function Team() {return (<h2>Team slot</h2><svg>...</svg>)}// app/dashboard/@revenue/page.tsxexport default function Revenue() {return (<h2>Revenue slot</h2><svg>...</svg>)}// app/dashboard/@analytics/page.tsxexport default function Analytics() {return (<h2>Analytics slot</h2><svg>...</svg>)}
{analytics: {...},},revenue: {...},},teams: {...},},children: {...}}
下一步是访问props对象的插槽属性,并在布局中动态渲染它们,如下所示:
import React from "react";interface ISlots {children: React.ReactNode;analytics: React.ReactNode;team: React.ReactNode;revenue: React.ReactNode;}export default function DashboardLayout(props: ISlots) {return (<div><h1>{props.children}</h1><div>{props.analytics}</div><div>{props.team}</div><div >{props.revenue}</div></div>);}
当你导航到localhost:3000/dashboard时,你应该会看到用并行路由渲染的仪表板布局:


import UserAnalytics from "@/components/Team";import RevenueMetrics from "@/components/Analytics";import Notifications from "@/components/Revenue";export default function DashboardLayout({children,}: {children: React.ReactNode;}) {return (<><div>{children}</div><UserAnalytics /><Revenue /><Team /></>);}

export default function Loading() {return <div>Loading...</div>;}
如果我们为插槽的加载时间添加不同的延迟,我们可以观察到这一特性的实际效果:
// wait function to add varying load timeexport function wait(time: number) {return new Promise((resolve) => {setTimeout(resolve, time);});}// app/dashboard/@team/page.tsxexport default async function Team() {Await wait(1000)return (<h2>Team slot</h2><svg>...</svg>)}// app/dashboard/@revenue/page.tsxexport default async function Revenue() {Await wait(2000)return (<h2>Revenue slot</h2><svg>...</svg>)}// app/dashboard/@analytics/page.tsxexport default async function Analytics() {Await wait(3000)return (<h2>Analytics slot</h2><svg>...</svg>)}


子导航

import React from "react";import Card from "@/components/card/card";import { wait } from "@/lib/wait/page";import Link from "next/link";// app/dashboard/@teamexport default async function Team() {return (<><h2>Teams slot</h2><svg>...</svg><Link href="/dashboard/members"><p>Got to /members page </p> </Link> </> ); } // app/dashboard/@team/members export default function Members() { return ( <> <h1>Members page</h1> <Link href="/dashboard"> <p> Got back to /teams page </p> </Link> </> ); }

注意,在某些情况下,当尝试导航回默认视图时,即/dashboard,你可能会遇到黑屏。这只是开发模式下的问题;如果你构建项目并运行生产版本,一切应该都可以正常工作。


条件路由
并行路由也可以根据某些条件有条件地渲染。例如,如果我们只希望经过身份验证的用户才能访问仪表板,我们可以使用身份验证状态,如果用户通过身份验证则渲染仪表板,否则渲染登录插槽:
interface ISlots {children: React.ReactNode;analytics: React.ReactNode;team: React.ReactNode;revenue: React.ReactNode;login: React.ReactNode}export default function DashboardLayout(props: ISlots) {const isLoggedIn = true; // Simulates auth stateif (!isLoggedIn) return props.login;return(<>{children}{users}{revenue}{notifications}</>);}
什么是拦截路由?



然后,我们定义当路由被拦截时要渲染的内容,如下所示:
interface IimageProps {params: {item: string;};}export default async function Page({ params: { item } }: IimageProps) {const res = await getImage(item);const image = await res.json();return (<><div><div><div><Imagesrc={image.urls.regular}alt={image.alt_description}priorityfillstyle={{ borderRadius: "10px" }}/></div></div><p>{image.alt_description}</p></div></>);}
目前,如果尝试通过 /products 路由访问任何项目的单独页面,则 URL 将更新为 localhost:3000/products/itemId,并且 /products/(.)[item] 的内容呈现拦截的路线,替换预期项目的内容


// app/products/layout.tsximport React from "react";export default function layout({children,modal,}: {children: React.ReactNode;modal: React.ReactNode;}) {return (<div>{children}{modal}</div>);}// app/products/@modal/default.tsxExport const Default = () => {return null;};
我们定义了 default.tsx 文件来防止 Next.js 在模态未激活时抛出 404 错误,并且因为我们不想在模态未激活时显示任何内容,所以我们返回 null 。
现在有了正确的样式,模态应该在拦截后正确呈现:

默认情况下,向后导航会关闭Modal,但如果您希望向模式添加执行此操作的图标或按钮,可以使用 router.back() ,如下面的代码所示:
'use client'import { useRouter } from 'next/navigation'export default function Page() {const router = useRouter()return (<div><span onClick={() => router.back()}>Close modal</span>...</div>)}
拦截模式
拦截路由约定的工作方式与相对路径约定 ../ 类似,这意味着我们可以使用不同级别定义拦截路由:
(..) 匹配同一级别的段
(..)(..) 匹配上面两级的段
(...) 匹配根级别的段
通过这些模式,我们可以在应用程序中的任何位置拦截路由。
结论
并行和拦截路由是 Next.js 中的高级路由机制,它们在构建 Web 应用程序时单独提供增强的灵活性和改进的用户体验。然而,当组合起来时,它们提供了更高级的功能,如本文所示。
并行和拦截路由是 Next.js 中的高级路由机制,它们在构建 Web 应用程序时单独提供增强的灵活性和改进的用户体验。然而,当组合起来时,它们提供了更高级的功能,如本文所示。
文章为作者独立观点,不代表DLZ123立场。如有侵权,请联系我们。( 版权为作者所有,如需转载,请联系作者 )
网站运营至今,离不开小伙伴们的支持。 为了给小伙伴们提供一个互相交流的平台和资源的对接,特地开通了独立站交流群。
群里有不少运营大神,不时会分享一些运营技巧,更有一些资源收藏爱好者不时分享一些优质的学习资料。
现在可以扫码进群,备注【加群】。 ( 群完全免费,不广告不卖课!)

发表评论 取消回复