المسارات المتوازية (Parallel Routes)
تتيح لك المسارات المتوازية (Parallel Routing) عرض صفحة واحدة أو أكثر في نفس التخطيط بشكل متزامن أو مشروط. للأجزاء الديناميكية للغاية في التطبيق، مثل لوحات التحكم والتغذيات في المواقع الاجتماعية، يمكن استخدام المسارات المتوازية لتنفيذ أنماط توجيه معقدة.
على سبيل المثال، يمكنك عرض صفحة الفريق وصفحة التحليلات في نفس الوقت.

تسمح المسارات المتوازية بتعريف حالات خطأ وتحميل مستقلة لكل مسار حيث يتم بثها بشكل مستقل.

تتيح المسارات المتوازية أيضًا عرض فتحة (slot) بشكل مشروط بناءً على شروط معينة، مثل حالة المصادقة. هذا يمكّن من فصل التعليمات البرمجية بالكامل على نفس الرابط.

الاصطلاح
يتم إنشاء المسارات المتوازية باستخدام فتحات (slots) مسماة. يتم تعريف الفتحات باستخدام اصطلاح @folder
، ويتم تمريرها إلى التخطيط بنفس المستوى كخصائص (props).
الفتحات ليست أجزاء من المسار (route segments) ولا تؤثر على بنية الرابط. مسار الملف
/@team/members
سيكون متاحًا على/members
.
على سبيل المثال، بنية الملف التالية تعرّف فتحتين صريحتين: @analytics
و @team
.

هيكل المجلد أعلاه يعني أن المكون في app/layout.js
يقبل الآن خصائص الفتحات @analytics
و @team
، ويمكن عرضها بالتوازي مع خاصية children
:
export default function Layout(props: {
children: React.ReactNode
analytics: React.ReactNode
team: React.ReactNode
}) {
return (
<>
{props.children}
{props.team}
{props.analytics}
</>
)
}
export default function Layout(props) {
return (
<>
{props.children}
{props.team}
{props.analytics}
</>
)
}
جيد للمعرفة: خاصية
children
هي فتحة ضمنية لا تحتاج إلى تعيين لمجلد. هذا يعني أنapp/page.js
تعادلapp/@children/page.js
.
المسارات غير المتطابقة
بشكل افتراضي، المحتوى المعروض داخل فتحة سيتطابق مع الرابط الحالي.
في حالة عدم تطابق فتحة، المحتوى الذي يعرضه Next.js يختلف بناءً على تقنية التوجيه وبنية المجلد.
default.js
يمكنك تعريف ملف default.js
ليتم عرضه كحل بديل عندما لا يتمكن Next.js من استعادة الحالة النشطة للفتحة بناءً على الرابط الحالي.
خذ بعين الاعتبار بنية المجلد التالية. فتحة @team
لديها مجلد settings
، لكن @analytics
لا تملكه.

التنقل
عند التنقل، سيعرض Next.js الحالة النشطة السابقة للفتحة، حتى لو لم تتطابق مع الرابط الحالي.
إعادة التحميل
عند إعادة التحميل، سيحاول Next.js أولاً عرض ملف default.js
للفتحة غير المتطابقة. إذا لم يكن متاحًا، سيتم عرض خطأ 404.
خطأ 404 للمسارات غير المتطابقة يساعد على ضمان عدم عرض مسار لا ينبغي عرضه بالتوازي.
useSelectedLayoutSegment(s)
كل من useSelectedLayoutSegment
و useSelectedLayoutSegments
يقبلان parallelRoutesKey
، مما يسمح لك بقراءة جزء المسار النشط داخل تلك الفتحة.
'use client'
import { useSelectedLayoutSegment } from 'next/navigation'
export default async function Layout(props: {
//...
auth: React.ReactNode
}) {
const loginSegments = useSelectedLayoutSegment('auth')
// ...
}
'use client'
import { useSelectedLayoutSegment } from 'next/navigation'
export default async function Layout(props) {
const loginSegments = useSelectedLayoutSegment('auth')
// ...
}
عندما ينتقل المستخدم إلى @auth/login
، أو /login
في شريط العناوين، loginSegments
ستكون مساوية للسلسلة "login"
.
أمثلة
النوافذ المنبثقة (Modals)
يمكن استخدام المسارات المتوازية لعرض النوافذ المنبثقة.

فتحة @auth
تعرض مكون <Modal>
يمكن إظهاره بالانتقال إلى مسار مطابق، مثل /login
.
export default async function Layout(props: {
// ...
auth: React.ReactNode
}) {
return (
<>
{/* ... */}
{props.auth}
</>
)
}
export default async function Layout(props) {
return (
<>
{/* ... */}
{props.auth}
</>
)
}
import { Modal } from 'components/modal'
export default function Login() {
return (
<Modal>
<h1>تسجيل الدخول</h1>
{/* ... */}
</Modal>
)
}
import { Modal } from 'components/modal'
export default function Login() {
return (
<Modal>
<h1>تسجيل الدخول</h1>
{/* ... */}
</Modal>
)
}
لضمان عدم عرض محتويات النافذة المنبثقة عندما لا تكون نشطة، يمكنك إنشاء ملف default.js
يعيد null
.
export default function Default() {
return null
}
export default function Default() {
return null
}
إغلاق نافذة منبثقة
إذا تم بدء النافذة المنبثقة من خلال التنقل من العميل، مثل استخدام <Link href="/login">
، يمكنك إغلاق النافذة المنبثقة عن طريق استدعاء router.back()
أو باستخدام مكون Link
.
'use client'
import { useRouter } from 'next/navigation'
import { Modal } from 'components/modal'
export default async function Login() {
const router = useRouter()
return (
<Modal>
<span onClick={() => router.back()}>إغلاق النافذة</span>
<h1>تسجيل الدخول</h1>
...
</Modal>
)
}
'use client'
import { useRouter } from 'next/navigation'
import { Modal } from 'components/modal'
export default async function Login() {
const router = useRouter()
return (
<Modal>
<span onClick={() => router.back()}>إغلاق النافذة</span>
<h1>تسجيل الدخول</h1>
...
</Modal>
)
}
المزيد من المعلومات حول النوافذ المنبثقة موجودة في قسم المسارات الاعتراضية (Intercepting Routes).
إذا كنت تريد الانتقال إلى مكان آخر وإغلاق نافذة منبثقة، يمكنك أيضًا استخدام مسار شامل (catch-all route).

export default function CatchAll() {
return null
}
export default function CatchAll() {
return null
}
المسارات الشاملة لها أولوية على
default.js
.
المسارات المشروطة
يمكن استخدام المسارات المتوازية لتنفيذ توجيه مشروط. على سبيل المثال، يمكنك عرض مسار @dashboard
أو @login
اعتمادًا على حالة المصادقة.
import { getUser } from '@/lib/auth'
export default function Layout({
dashboard,
login,
}: {
dashboard: React.ReactNode
login: React.ReactNode
}) {
const isLoggedIn = getUser()
return isLoggedIn ? dashboard : login
}
import { getUser } from '@/lib/auth'
export default function Layout({ dashboard, login }) {
const isLoggedIn = getUser()
return isLoggedIn ? dashboard : login
}
