مسیرهای موازی
مسیرهای موازی به شما امکان می دهد تا به طور همزمان یا مشروط، یک یا چند صفحه را در یک چیدمان (layout) واحد رندر کنید. این مسیرها برای بخش های بسیار داینامیک در یک برنامه، مانند داشبوردها و فیدهای شبکه های اجتماعی مفید هستند.
به عنوان مثال، با در نظر گرفتن یک داشبورد، می توانید از مسیرهای موازی برای رندر همزمان صفحات team و analytics استفاده کنید:

اسلاتها (Slots)
مسیرهای موازی با استفاده از اسلاتهای نامگذاری شده ایجاد می شوند. اسلات ها با قرارداد @folder تعریف می شوند. به عنوان مثال، ساختار فایل زیر دو اسلات را تعریف می کند: @analytics و @team

اسلات ها به عنوان prop به layout والد مشترک منتقل می شوند. برای مثال بالا، کامپوننت در app/layout.js اکنون prop های @analytics و @team را می پذیرد و می تواند آنها را به طور موازی در کنار prop children رندر کند.
export default function Layout({
children,
team,
analytics,
}: {
children: React.ReactNode
analytics: React.ReactNode
team: React.ReactNode
}) {
return (
<>
{children}
{team}
{analytics}
</>
)
}با این حال، اسلاتها بخش های مسیر نیستند و بر ساختار URL تأثیر نمیگذارند. برای مثال، برای /@analytics/views، URL برابر با /views خواهد بود زیرا @analytics یک اسلات است.
خوب است بدانید:
- prop
childrenیک اسلات ضمنی است که نیازی به نگاشت به یک پوشه ندارد. این به این معنی است کهapp/page.jsمعادل باapp/@children/page.jsاست.
حالت فعال و پیمایش
به طور پیش فرض، Next.js برای هر اسلات، ردیفی از حالت فعال (یا زیرصفحه) نگه می دارد. با این حال، محتوای رندر شده درون یک اسلات به نوع پیمایش بستگی دارد:
- ناوبری نرم (Soft Navigation): در طول پیمایش سمت کاربر، Next.js یک رندر جزئی انجام می دهد، زیرصفحه درون اسلات را تغییر می دهد، در حالی که زیرصفحات فعال اسلات های دیگر را حتی اگر با URL فعلی مطابقت ندارند، حفظ می کند.
- ناوبری سخت (Hard Navigation): پس از بارگذاری کامل صفحه (browser refresh)، Next.js نمی تواند حالت فعال را برای اسلات هایی که با URL فعلی مطابقت ندارند، تعیین کند. در عوض، یک فایل
default.jsرا برای اسلات های بدون تطابق رندر می کند، یا اگرdefault.jsوجود ندارد، خطای404را نمایش می دهد.
خوب است بدانید:
- خطای
404برای مسیرهای بدون تطابق به جلوگیری از رندر تصادفی یک مسیر موازی در صفحه ای که برای آن در نظر گرفته نشده کمک می کند.
default.js
می توانید یک فایل default.js را برای رندر به عنوان یک پشتیبان برای اسلات های بدون تطابق در هنگام بارگذاری اولیه یا بارگذاری مجدد کل صفحه تعریف کنید.
ساختار پوشه زیر را در نظر بگیرید. اسلات @team یک صفحه /settings دارد، اما اسلات @analytics ندارد.

هنگام پیمایش به /settings، اسلات @team صفحه /settings را رندر می کند و در عین حال صفحه فعال فعلی را برای اسلات @analytics حفظ می کند.
در زمان رفرش، Next.js یک default.js را برای @analytics رندر خواهد کرد. اگر default.js وجود نداشته باشد، به جای آن خطای 404 نمایش داده می شود.
علاوه بر این، از آنجایی که children یک اسلات ضمنی است، شما همچنین نیاز به ایجاد یک فایل default.js برای رندر یک پشتیبان برای children در زمانی که Next.js نمی تواند حالت فعال صفحه والد را بازیابی کند، دارید.
useSelectedLayoutSegment(s)
هر دو useSelectedLayoutSegment و useSelectedLayoutSegments پارامتر parallelRoutesKey را می پذیرند که به شما امکان می دهد بخش مسیر فعال را در یک اسلات بخوانید.
'use client'
import { useSelectedLayoutSegment } from 'next/navigation'
export default function Layout({ auth }: { auth: React.ReactNode }) {
const loginSegment = useSelectedLayoutSegment('auth')
// ...
}وقتی کاربر به app/@auth/login (یا /login در نوار URL) پیمایش می کند، loginSegment برابر با رشته "login" خواهد بود.
مثال ها
مسیرهای شرطی
میتوانید از مسیرهای موازی برای رندر شرطی مسیرها بر اساس شرایط خاص، مانند نقش کاربر استفاده کنید. به عنوان مثال، برای رندر کردن یک صفحه داشبورد متفاوت برای نقش های /admin یا /user:

import { checkUserRole } from '@/lib/auth'
export default function Layout({
user,
admin,
}: {
user: React.ReactNode
admin: React.ReactNode
}) {
const role = checkUserRole()
return <>{role === 'admin' ? admin : user}</>
}گروههای تب
میتوانید یک layout را در داخل یک اسلات اضافه کنید تا به کاربران اجازه دهید به صورت مستقل در اسلات پیمایش کنند. این برای ایجاد تب ها مفید است.
برای مثال، اسلات @analytics دارای دو زیرصفحه است: /page-views و /visitors.

در داخل @analytics، یک فایل layout برای به اشتراک گذاشتن تب ها بین دو صفحه ایجاد کنید:
import Link from 'next/link'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<nav>
<Link href="/page-views">Page Views</Link>
<Link href="/visitors">Visitors</Link>
</nav>
<div>{children}</div>
</>
)
}مودال ها
مسیرهای موازی را میتوان همراه با رهگیری مسیرها (Intercepting Routes) برای ایجاد مودالها استفاده کرد. این به شما امکان می دهد چالش های رایج هنگام ساخت مودال ها را حل کنید، مانند:
- امکان اشتراک گذاری محتوای مودال از طریق URL.
- حفظ زمینه Preserving context زمانی که صفحه تازه سازی می شود، به جای بستن مودال.
- Closing the modal on backwards navigation rather than going to the previous route.
- بستن مودال در پیمایش به عقب به جای رفتن به مسیر قبلی.
- باز کردن مجدد مودال در پیمایش به جلو.
الگوی رابط کاربری زیر را در نظر بگیرید که در آن کاربر می تواند یک مودال ورود را از یک layout با استفاده از پیمایش سمت کاربر باز کند یا به یک صفحه جداگانه /login دسترسی پیدا کند:

برای اجرای این الگو، ابتدا با ایجاد مسیری به نام /login شروع کنید که صفحه اصلی ورود شما را رندر می کند.

import { Login } from '@/app/ui/login'
export default function Page() {
return <Login />
}سپس، داخل اسلات @auth، یک فایل default.js اضافه کنید که null را برمی گرداند. این تضمین می کند که مودال زمانی که فعال نیست، رندر نمی شود.
export default function Default() {
return null
}در داخل اسلات @auth، مسیر /login را با به روز رسانی پوشه /(.)login رهگیری کنید. کامپوننت <Modal> و فرزندان آن را به فایل /(.)login/page.tsx وارد کنید:
import { Modal } from '@/app/ui/modal'
import { Login } from '@/app/ui/login'
export default function Page() {
return (
<Modal>
<Login />
</Modal>
)
}خوب است بدانید:
- قراردادی که برای رهگیری مسیر intercept the route استفاده می شود، مانند
(.)، به ساختار سیستم فایل شما بستگی دارد. به قرارداد رهگیری مسیرها مراجعه کنید.- با جدا کردن عملکرد
<Modal>از محتوای مودال (<Login>)، می توانید اطمینان حاصل کنید که هر محتوایی داخل مودال، مانند فرم ها، Server Components هستند. برای اطلاعات بیشتر به ترکیب Client و Server Components مراجعه کنید.
باز کردن مودال
حالا می توانید از روتر Next.js برای باز کردن و بستن مودال استفاده کنید. این تضمین می کند که URL زمانی که مودال باز است و هنگام پیمایش به عقب و جلو به درستی به روز شود.
برای باز کردن مودال، اسلات @auth را به عنوان یک پراپ به طرح بندی والد منتقل کرده و آن را در کنار پراپ children رندر کنید.
import Link from 'next/link'
export default function Layout({
auth,
children,
}: {
auth: React.ReactNode
children: React.ReactNode
}) {
return (
<>
<nav>
<Link href="/login">Open modal</Link>
</nav>
<div>{auth}</div>
<div>{children}</div>
</>
)
}هنگامی که کاربر روی <Link> کلیک می کند، به جای پیمایش به صفحه /login، مودال باز خواهد شد. با این حال، در زمان رفرش یا بارگذاری اولیه، پیمایش به /login کاربر را به صفحه اصلی ورود هدایت می کند.
بستن مودال
می توانید با فراخوانی router.back() یا با استفاده از کامپوننت <Link>، مودال را ببندید.
'use client'
import { useRouter } from 'next/navigation'
export function Modal({ children }: { children: React.ReactNode }) {
const router = useRouter()
return (
<>
<button
onClick={() => {
router.back()
}}
>
Close modal
</button>
<div>{children}</div>
</>
)
}هنگام استفاده از کامپوننت <Link> برای پیمایش خارج از صفحه ای که دیگر نباید اسلات @auth را رندر کند، از یک مسیر همه گیر استفاده می کنیم که null را برمی گرداند.
import Link from 'next/link'
export function Modal({ children }: { children: React.ReactNode }) {
return (
<>
<Link href="/">Close modal</Link>
<div>{children}</div>
</>
)
}export default function CatchAll() {
return null
}خوب است بدانید:
- ما از یک مسیر همه گیر در اسلات
@authبرای بستن مودال به دلیل رفتاری که در حالت فعال و پیمایش توضیح داده شده است استفاده می کنیم. از آنجایی که پیمایشهای سمت کاربر به مسیری که دیگر با اسلات مطابقت ندارد، همچنان قابل مشاهده خواهند بود، باید اسلات را با مسیری کهnullرا برمیگرداند مطابقت دهیم تا مودال بسته شود.- نمونههای دیگر میتوانند شامل باز کردن یک مودال عکس در یک گالری در حالی که یک صفحه اختصاصی
/photo/[id]نیز وجود داشته باشد، یا باز کردن یک سبد خرید در یک مودال جانبی باشند.- نمونهای از استفاده از مسیرهای موازی با رهگیری مسیرها و مودالها را در اینجا مشاهده کنید: مشاهده مثال (opens in a new tab).
رابط کاربری بارگیری و خطا
مسیرهای موازی را میتوان به طور مستقل استریم کرد و به شما این امکان را میدهد که حالتهای خطا و بارگیری مستقل را برای هر مسیر تعریف کنید:

برای اطلاعات بیشتر به مستندات رابط کاربری بارگذاری و هندل کردن خطا مراجعه کنید.