Next.js 在 2016 年發(fā)布時(shí)的競(jìng)爭(zhēng)優(yōu)勢(shì)之一是其內(nèi)置的路由系統(tǒng)。它同時(shí)支持客戶端和服務(wù)器端渲染,因此開(kāi)發(fā)人員無(wú)需配置像 React Router DOM 這樣的第三方路由庫(kù)。Next.js 的路由器也是基于文件系統(tǒng)的,這意味著應(yīng)用程序中的路由由文件和文件夾的組織方式?jīng)Q定。這使得它對(duì)大多數(shù)開(kāi)發(fā)人員更具吸引力。

Vercel 團(tuán)隊(duì)一直在通過(guò)每個(gè)新版本改進(jìn)路由系統(tǒng)。Next.js 9 引入了 API 路由,讓開(kāi)發(fā)人員可以創(chuàng)建處理特定 API 端點(diǎn)的無(wú)服務(wù)器函數(shù)。Next.js 13 引入了 App Router,這是一種新的路由約定,可讓您在同一應(yīng)用程序中渲染客戶端和服務(wù)器端 React 組件。
App Router 具有許多功能,包括布局、動(dòng)態(tài)路由、嵌套路由以及一組稱為并行和相交路由的新路由約定。這些功能可用于創(chuàng)建高級(jí)路由模式。
在本文中,我們將探討什么是平行和相交路線,將它們與現(xiàn)有的路線選項(xiàng)進(jìn)行比較,了解它們的約定,并演示如何使用它們。
先決條件
預(yù)先了解 Next.js 將有助于閱讀本文,但如果您對(duì) React 有深入的了解,則不需要了解這些知識(shí)
什么是并行路由?
并行路由是 Next.js 中一種新的高級(jí)路由約定。根據(jù)文檔:
“并行路由是一種 Next.js 路由范例,它允許您同時(shí)或有條件地在同一布局中渲染一個(gè)或多個(gè)頁(yè)面,這些頁(yè)面可以獨(dú)立導(dǎo)航。”
換句話說(shuō),并行路由允許您在同一視圖中渲染多個(gè)頁(yè)面。
并行路由在渲染應(yīng)用程序的復(fù)雜動(dòng)態(tài)部分時(shí)最有用,例如在具有多個(gè)獨(dú)立部分或模態(tài)的儀表板中。
下圖是 Next 文檔中的儀表板頁(yè)面的插圖,演示了并行路線的復(fù)雜性:

在這種情況下,@team和@analytics路線使用并行路由同時(shí)呈現(xiàn)為儀表板布局的部分。
并行路由使用@folder約定來(lái)定義,也稱為"插槽",本質(zhì)上是一個(gè)以@符號(hào)為前綴的文件夾:


為簡(jiǎn)單起見(jiàn),我們將在插槽中包含占位符內(nèi)容,如下所示:
// 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: {...}}
下一步是訪問(wèn)props對(duì)象的插槽屬性,并在布局中動(dòng)態(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>);}
當(dāng)你導(dǎo)航到localhost:3000/dashboard時(shí),你應(yīng)該會(huì)看到用并行路由渲染的儀表板布局:


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時(shí)間添加不同的延遲,我們可以觀察到這一特性的實(shí)際效果:
// 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>)}


子導(dǎo)航

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> </> ); }

注意,在某些情況下,當(dāng)嘗試導(dǎo)航回默認(rèn)視圖時(shí),即/dashboard,你可能會(huì)遇到黑屏。這只是開(kāi)發(fā)模式下的問(wèn)題;如果你構(gòu)建項(xiàng)目并運(yùn)行生產(chǎn)版本,一切應(yīng)該都可以正常工作。


條件路由?
并行路由也可以根據(jù)某些條件有條件地渲染。例如,如果我們只希望經(jīng)過(guò)身份驗(yàn)證的用戶才能訪問(wèn)儀表板,我們可以使用身份驗(yàn)證狀態(tài),如果用戶通過(guò)身份驗(yàn)證則渲染儀表板,否則渲染登錄插槽:
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}</>);}
什么是攔截路由?



然后,我們定義當(dāng)路由被攔截時(shí)要渲染的內(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><Imagesrc={image.urls.regular}alt={image.alt_description}priorityfillstyle={{ borderRadius: "10px" }}/></div></div><p>{image.alt_description}</p></div></>);}
目前,如果嘗試通過(guò) /products 路由訪問(wèn)任何項(xiàng)目的單獨(dú)頁(yè)面,則 URL 將更新為 localhost:3000/products/itemId,并且 /products/(.)[item] 的內(nèi)容呈現(xiàn)攔截的路線,替換預(yù)期項(xiàng)目的內(nèi)容


// 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 文件來(lái)防止 Next.js 在模態(tài)未激活時(shí)拋出 404 錯(cuò)誤,并且因?yàn)槲覀儾幌朐谀B(tài)未激活時(shí)顯示任何內(nèi)容,所以我們返回 null 。
現(xiàn)在有了正確的樣式,模態(tài)應(yīng)該在攔截后正確呈現(xiàn):

默認(rèn)情況下,向后導(dǎo)航會(huì)關(guān)閉Modal,但如果您希望向模式添加執(zhí)行此操作的圖標(biāo)或按鈕,可以使用 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>)}
攔截模式
攔截路由約定的工作方式與相對(duì)路徑約定 ../ 類似,這意味著我們可以使用不同級(jí)別定義攔截路由:
(..)?匹配同一級(jí)別的段
(..)(..)?匹配上面兩級(jí)的段
(...)?匹配根級(jí)別的段
通過(guò)這些模式,我們可以在應(yīng)用程序中的任何位置攔截路由。
結(jié)論
并行和攔截路由是 Next.js 中的高級(jí)路由機(jī)制,它們?cè)跇?gòu)建 Web 應(yīng)用程序時(shí)單獨(dú)提供增強(qiáng)的靈活性和改進(jìn)的用戶體驗(yàn)。然而,當(dāng)組合起來(lái)時(shí),它們提供了更高級(jí)的功能,如本文所示。
并行和攔截路由是 Next.js 中的高級(jí)路由機(jī)制,它們?cè)跇?gòu)建 Web 應(yīng)用程序時(shí)單獨(dú)提供增強(qiáng)的靈活性和改進(jìn)的用戶體驗(yàn)。然而,當(dāng)組合起來(lái)時(shí),它們提供了更高級(jí)的功能,如本文所示。
文章為作者獨(dú)立觀點(diǎn),不代表DLZ123立場(chǎng)。如有侵權(quán),請(qǐng)聯(lián)系我們。( 版權(quán)為作者所有,如需轉(zhuǎn)載,請(qǐng)聯(lián)系作者 )
網(wǎng)站運(yùn)營(yíng)至今,離不開(kāi)小伙伴們的支持。 為了給小伙伴們提供一個(gè)互相交流的平臺(tái)和資源的對(duì)接,特地開(kāi)通了獨(dú)立站交流群。
群里有不少運(yùn)營(yíng)大神,不時(shí)會(huì)分享一些運(yùn)營(yíng)技巧,更有一些資源收藏愛(ài)好者不時(shí)分享一些優(yōu)質(zhì)的學(xué)習(xí)資料。
現(xiàn)在可以掃碼進(jìn)群,備注【加群】。 ( 群完全免費(fèi),不廣告不賣課!)
