Next.js 在 2016 年發(fā)布時的競爭優(yōu)勢之一是其內(nèi)置的路由系統(tǒng)。它同時支持客戶端和服務(wù)器端渲染,因此開發(fā)人員無需配置像 React Router DOM 這樣的第三方路由庫。Next.js 的路由器也是基于文件系統(tǒng)的,這意味著應用程序中的路由由文件和文件夾的組織方式?jīng)Q定。這使得它對大多數(shù)開發(fā)人員更具吸引力。
Vercel 團隊一直在通過每個新版本改進路由系統(tǒng)。Next.js 9 引入了 API 路由,讓開發(fā)人員可以創(chuàng)建處理特定 API 端點的無服務(wù)器函數(shù)。Next.js 13 引入了 App Router,這是一種新的路由約定,可讓您在同一應用程序中渲染客戶端和服務(wù)器端 React 組件。
App Router 具有許多功能,包括布局、動態(tài)路由、嵌套路由以及一組稱為并行和相交路由的新路由約定。這些功能可用于創(chuàng)建高級路由模式。
在本文中,我們將探討什么是平行和相交路線,將它們與現(xiàn)有的路線選項進行比較,了解它們的約定,并演示如何使用它們。
先決條件
預先了解 Next.js 將有助于閱讀本文,但如果您對 React 有深入的了解,則不需要了解這些知識
什么是并行路由?
并行路由是 Next.js 中一種新的高級路由約定。根據(jù)文檔:
“并行路由是一種 Next.js 路由范例,它允許您同時或有條件地在同一布局中渲染一個或多個頁面,這些頁面可以獨立導航。”
換句話說,并行路由允許您在同一視圖中渲染多個頁面。
并行路由在渲染應用程序的復雜動態(tài)部分時最有用,例如在具有多個獨立部分或模態(tài)的儀表板中。
下圖是 Next 文檔中的儀表板頁面的插圖,演示了并行路線的復雜性:
在這種情況下,@team
和@analytics
路線使用并行路由同時呈現(xiàn)為儀表板布局的部分。
并行路由使用@folder約定來定義,也稱為"插槽",本質(zhì)上是一個以@符號為前綴的文件夾:
為簡單起見,我們將在插槽中包含占位符內(nèi)容,如下所示:
// 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對象的插槽屬性,并在布局中動態(tài)渲染它們,如下所示:
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>;
}
如果我們?yōu)椴宀鄣募虞d時間添加不同的延遲,我們可以觀察到這一特性的實際效果:
// 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,你可能會遇到黑屏。這只是開發(fā)模式下的問題;如果你構(gòu)建項目并運行生產(chǎn)版本,一切應該都可以正常工作。
條件路由?
并行路由也可以根據(jù)某些條件有條件地渲染。例如,如果我們只希望經(jīng)過身份驗證的用戶才能訪問儀表板,我們可以使用身份驗證狀態(tài),如果用戶通過身份驗證則渲染儀表板,否則渲染登錄插槽:
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}
</>
);
}
什么是攔截路由?
然后,我們定義當路由被攔截時要渲染的內(nèi)容,如下所示:
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] 的內(nèi)容呈現(xiàn)攔截的路線,替換預期項目的內(nèi)容
// 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 在模態(tài)未激活時拋出 404 錯誤,并且因為我們不想在模態(tài)未激活時顯示任何內(nèi)容,所以我們返回 null 。
現(xiàn)在有了正確的樣式,模態(tài)應該在攔截后正確呈現(xiàn):
默認情況下,向后導航會關(guān)閉Modal,但如果您希望向模式添加執(zhí)行此操作的圖標或按鈕,可以使用 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>
)
}
攔截模式
攔截路由約定的工作方式與相對路徑約定 ../ 類似,這意味著我們可以使用不同級別定義攔截路由:
(..)?匹配同一級別的段
(..)(..)?匹配上面兩級的段
(...)?匹配根級別的段
通過這些模式,我們可以在應用程序中的任何位置攔截路由。
結(jié)論
并行和攔截路由是 Next.js 中的高級路由機制,它們在構(gòu)建 Web 應用程序時單獨提供增強的靈活性和改進的用戶體驗。然而,當組合起來時,它們提供了更高級的功能,如本文所示。
并行和攔截路由是 Next.js 中的高級路由機制,它們在構(gòu)建 Web 應用程序時單獨提供增強的靈活性和改進的用戶體驗。然而,當組合起來時,它們提供了更高級的功能,如本文所示。
文章為作者獨立觀點,不代表DLZ123立場。如有侵權(quán),請聯(lián)系我們。( 版權(quán)為作者所有,如需轉(zhuǎn)載,請聯(lián)系作者 )

網(wǎng)站運營至今,離不開小伙伴們的支持。 為了給小伙伴們提供一個互相交流的平臺和資源的對接,特地開通了獨立站交流群。
群里有不少運營大神,不時會分享一些運營技巧,更有一些資源收藏愛好者不時分享一些優(yōu)質(zhì)的學習資料。
現(xiàn)在可以掃碼進群,備注【加群】。 ( 群完全免費,不廣告不賣課!)