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.tsx
export default function Team() {
return (
<h2>Team slot</h2>
<svg>...</svg>
)
}
// app/dashboard/@revenue/page.tsx
export default function Revenue() {
return (
<h2>Revenue slot</h2>
<svg>...</svg>
)
}
// app/dashboard/@analytics/page.tsx
export 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 time
export function wait(time: number) {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
}
// app/dashboard/@team/page.tsx
export default async function Team() {
Await wait(1000)
return (
<h2>Team slot</h2>
<svg>...</svg>
)
}
// app/dashboard/@revenue/page.tsx
export default async function Revenue() {
Await wait(2000)
return (
<h2>Revenue slot</h2>
<svg>...</svg>
)
}
// app/dashboard/@analytics/page.tsx
export 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/@team
export 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 state
if (!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>
<Image
src={image.urls.regular}
alt={image.alt_description}
priority
fill
style={{ borderRadius: "10px" }}
/>
</div>
</div>
<p>{image.alt_description}</p>
</div>
</>
);
}
目前,如果尝试通过 /products 路由访问任何项目的单独页面,则 URL 将更新为 localhost:3000/products/itemId,并且 /products/(.)[item] 的内容呈现拦截的路线,替换预期项目的内容
// app/products/layout.tsx
import React from "react";
export default function layout({
children,
modal,
}: {
children: React.ReactNode;
modal: React.ReactNode;
}) {
return (
<div>
{children}
{modal}
</div>
);
}
// app/products/@modal/default.tsx
Export 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立场。如有侵权,请联系我们。( 版权为作者所有,如需转载,请联系作者 )
网站运营至今,离不开小伙伴们的支持。 为了给小伙伴们提供一个互相交流的平台和资源的对接,特地开通了独立站交流群。
群里有不少运营大神,不时会分享一些运营技巧,更有一些资源收藏爱好者不时分享一些优质的学习资料。
现在可以扫码进群,备注【加群】。 ( 群完全免费,不广告不卖课!)
发表评论 取消回复