أطلق العنان لواجهات مستخدم ديناميكية وقابلة للتوسع في Next.js. يغطي دليلنا الشامل مجموعات المسارات للتنظيم والمسارات المتوازية للوحات التحكم المعقدة. ارتقِ بمستواك الآن!
إتقان موجّه التطبيقات في Next.js: نظرة معمقة على بنية مجموعات المسارات والمسارات المتوازية
شكّل إصدار موجّه التطبيقات (App Router) في Next.js نقلة نوعية في كيفية بناء المطورين لتطبيقات الويب باستخدام إطار عمل React الشهير. بالابتعاد عن الاصطلاحات القائمة على الملفات في موجّه الصفحات (Pages Router)، قدّم موجّه التطبيقات نموذجًا أكثر قوة ومرونة وتركيزًا على الخادم. هذا التطور يمكّننا من إنشاء واجهات مستخدم معقدة وعالية الأداء مع قدر أكبر من التحكم والتنظيم. ومن بين أبرز الميزات التحويلية التي تم تقديمها هي مجموعات المسارات (Route Groups) والمسارات المتوازية (Parallel Routes).
بالنسبة للمطورين الذين يهدفون إلى بناء تطبيقات على مستوى الشركات، فإن إتقان هذين المفهومين ليس مجرد أمر مفيد—بل هو ضروري. فهما يحلان تحديات معمارية شائعة تتعلق بإدارة التخطيط، وتنظيم المسارات، وإنشاء واجهات ديناميكية متعددة الأجزاء مثل لوحات التحكم. يقدم هذا الدليل استكشافًا شاملًا لمجموعات المسارات والمسارات المتوازية، منتقلًا من المفاهيم التأسيسية إلى استراتيجيات التنفيذ المتقدمة وأفضل الممارسات لجمهور المطورين العالمي.
فهم موجّه التطبيقات في Next.js: مراجعة سريعة
قبل أن نتعمق في التفاصيل، دعنا نراجع بإيجاز المبادئ الأساسية لموجّه التطبيقات. تعتمد بنيته على نظام قائم على المجلدات حيث تحدد المجلدات أجزاء عنوان URL. وتحدد الملفات الخاصة داخل هذه المجلدات واجهة المستخدم وسلوك ذلك الجزء:
page.js
: مكون واجهة المستخدم الرئيسي للمسار، مما يجعله متاحًا للعموم.layout.js
: مكون واجهة مستخدم يلتف حول التخطيطات أو الصفحات الفرعية. وهو ضروري لمشاركة واجهة المستخدم عبر مسارات متعددة، مثل الترويسات والتذييلات.loading.js
: واجهة مستخدم اختيارية لعرضها أثناء تحميل محتوى الصفحة، مبنية على React Suspense.error.js
: واجهة مستخدم اختيارية لعرضها في حالة حدوث أخطاء، مما ينشئ حدود أخطاء قوية.
هذه البنية، جنبًا إلى جنب مع الاستخدام الافتراضي لمكونات خادم React (RSCs)، تشجع على نهج يركز على الخادم أولًا والذي يمكن أن يحسن بشكل كبير الأداء وأنماط جلب البيانات. تعد مجموعات المسارات والمسارات المتوازية اصطلاحات متقدمة تبني على هذا الأساس.
إزالة الغموض عن مجموعات المسارات: تنظيم مشروعك من أجل الوضوح والقابلية للتوسع
مع نمو التطبيق، يمكن أن يصبح عدد المسارات غير عملي. قد يكون لديك مجموعة من الصفحات للتسويق، وأخرى لتوثيق المستخدم، وثالثة للوحة التحكم الأساسية للتطبيق. منطقيًا، هذه أقسام منفصلة، ولكن كيف تنظمها في نظام الملفات الخاص بك دون تشويش عناوين URL الخاصة بك؟ هذه هي بالضبط المشكلة التي تحلها مجموعات المسارات.
ما هي مجموعات المسارات؟
مجموعة المسارات هي آلية لتنظيم ملفاتك وأجزاء المسار في مجموعات منطقية دون التأثير على بنية عنوان URL. يمكنك إنشاء مجموعة مسارات عن طريق وضع اسم المجلد بين قوسين، على سبيل المثال، (marketing)
أو (app)
.
اسم المجلد داخل القوسين هو لأغراض تنظيمية بحتة. يتجاهله Next.js تمامًا عند تحديد مسار URL. على سبيل المثال، الملف الموجود في app/(marketing)/about/page.js
سيتم تقديمه على عنوان URL /about
، وليس /(marketing)/about
.
حالات الاستخدام الرئيسية وفوائد مجموعات المسارات
في حين أن التنظيم البسيط هو فائدة، تكمن القوة الحقيقية لمجموعات المسارات في قدرتها على تقسيم تطبيقك إلى أقسام ذات تخطيطات مشتركة ومميزة.
1. إنشاء تخطيطات مختلفة لأجزاء المسار
هذه هي حالة الاستخدام الأكثر شيوعًا وقوة. تخيل تطبيق ويب به قسمان رئيسيان:
- موقع تسويقي عام (الرئيسية، حول، الأسعار) مع ترويسة وتذييل عالميين.
- لوحة تحكم خاصة للمستخدمين الموثقين (لوحة التحكم، الإعدادات، الملف الشخصي) مع شريط جانبي، وتنقل خاص بالمستخدم، وبنية عامة مختلفة.
بدون مجموعات المسارات، سيكون تطبيق تخطيطات جذر مختلفة على هذه الأقسام معقدًا. مع مجموعات المسارات، يصبح الأمر بديهيًا بشكل لا يصدق. يمكنك إنشاء ملف layout.js
فريد داخل كل مجموعة.
فيما يلي بنية ملف نموذجية لهذا السيناريو:
app/
├── (marketing)/
│ ├── layout.js // تخطيط عام مع ترويسة/تذييل تسويقي
│ ├── page.js // يُعرض عند '/'
│ └── about/
│ └── page.js // يُعرض عند '/about'
├── (app)/
│ ├── layout.js // تخطيط لوحة التحكم مع شريط جانبي
│ ├── dashboard/
│ │ └── page.js // يُعرض عند '/dashboard'
│ └── settings/
│ └── page.js // يُعرض عند '/settings'
└── layout.js // التخطيط الجذري (مثل وسوم <html> و <body>)
في هذه البنية:
- سيتم تغليف أي مسار داخل مجموعة
(marketing)
بواسطة(marketing)/layout.js
. - سيتم تغليف أي مسار داخل مجموعة
(app)
بواسطة(app)/layout.js
. - تتشارك كلتا المجموعتين في التخطيط الجذري
app/layout.js
، وهو مثالي لتعريف بنية HTML العالمية.
2. استبعاد جزء من المسار من التخطيط المشترك
أحيانًا، تحتاج صفحة أو قسم معين إلى التحرر من التخطيط الأصلي تمامًا. مثال شائع هو عملية الدفع أو صفحة هبوط خاصة لا ينبغي أن تحتوي على تنقل الموقع الرئيسي. يمكنك تحقيق ذلك عن طريق وضع المسار في مجموعة لا تشارك التخطيط الأعلى مستوى. على الرغم من أن هذا يبدو معقدًا، إلا أنه يعني ببساطة إعطاء مجموعة المسارات ملف layout.js
خاص بها على المستوى الأعلى لا يعرض `children` من التخطيط الجذري.
مثال عملي: بناء تطبيق متعدد التخطيطات
دعنا نبني نسخة مصغرة من بنية التسويق/التطبيق الموصوفة أعلاه.
1. التخطيط الجذري (app/layout.js
)
هذا التخطيط بسيط جدًا وينطبق على كل صفحة. يحدد بنية HTML الأساسية.
// app/layout.js
export default function RootLayout({ children }) {
return (
<html lang="ar">
<body>{children}</body>
</html>
);
}
2. تخطيط التسويق (app/(marketing)/layout.js
)
يتضمن هذا التخطيط ترويسة وتذييلاً للواجهة العامة.
// app/(marketing)/layout.js
export default function MarketingLayout({ children }) {
return (
<div>
<header>ترويسة تسويقية</header>
<main>{children}</main>
<footer>تذييل تسويقي</footer>
</div>
);
}
3. تخطيط لوحة تحكم التطبيق (app/(app)/layout.js
)
يحتوي هذا التخطيط على بنية مختلفة، ويتميز بشريط جانبي للمستخدمين الموثقين.
// app/(app)/layout.js
export default function AppLayout({ children }) {
return (
<div style={{ display: 'flex' }}>
<aside style={{ width: '200px', borderRight: '1px solid #ccc' }}>
الشريط الجانبي للوحة التحكم
</aside>
<main style={{ flex: 1, padding: '20px' }}>{children}</main>
</div>
);
}
مع هذه البنية، سيؤدي الانتقال إلى /about
إلى عرض الصفحة باستخدام `MarketingLayout`، بينما سيؤدي الانتقال إلى /dashboard
إلى عرضها باستخدام `AppLayout`. يظل عنوان URL نظيفًا ودلاليًا، بينما تكون بنية ملفات مشروعنا منظمة تمامًا وقابلة للتطوير.
إطلاق العنان لواجهات المستخدم الديناميكية باستخدام المسارات المتوازية
بينما تساعد مجموعات المسارات في تنظيم أقسام مميزة من التطبيق، تعالج المسارات المتوازية تحديًا مختلفًا: عرض طرق عرض صفحات متعددة ومستقلة ضمن تخطيط واحد. هذا مطلب شائع للوحات التحكم المعقدة، أو خلاصات الوسائط الاجتماعية، أو أي واجهة مستخدم حيث تحتاج أجزاء مختلفة إلى العرض والإدارة في وقت واحد.
ما هي المسارات المتوازية؟
تسمح لك المسارات المتوازية بعرض صفحة واحدة أو أكثر في نفس الوقت ضمن نفس التخطيط. يتم تعريف هذه المسارات باستخدام اصطلاح مجلد خاص يسمى الفتحات (slots). يتم إنشاء الفتحات باستخدام صيغة @folderName
. وهي ليست جزءًا من بنية عنوان URL؛ بدلاً من ذلك، يتم تمريرها تلقائيًا كخصائص (props) إلى أقرب ملف `layout.js` رئيسي مشترك.
على سبيل المثال، إذا كان لديك تخطيط يحتاج إلى عرض موجز لنشاط الفريق ومخطط تحليلات جنبًا إلى جنب، يمكنك تحديد فتحتين: `@team` و `@analytics`.
الفكرة الأساسية: الفتحات (Slots)
فكر في الفتحات كعناصر نائبة مسماة في تخطيطك. يقبل ملف التخطيط هذه الفتحات صراحةً كخصائص ويقرر مكان عرضها.
تأمل مكون التخطيط هذا:
// تخطيط يقبل فتحتين: 'team' و 'analytics'
export default function DashboardLayout({ children, team, analytics }) {
return (
<div>
{children}
<div style={{ display: 'flex' }}>
{team}
{analytics}
</div>
</div>
);
}
هنا، `children` و `team` و `analytics` كلها فتحات. `children` هي فتحة ضمنية تتوافق مع ملف `page.js` القياسي في الدليل. `team` و `analytics` هما فتحتان صريحتان يجب إنشاؤهما بالبادئة `@` في نظام الملفات.
الميزات والمزايا الرئيسية
- معالجة مسارات مستقلة: يمكن أن يكون لكل مسار متوازي (فتحة) حالات تحميل وأخطاء خاصة به. هذا يعني أن لوحة التحليلات الخاصة بك يمكن أن تعرض مؤشر تحميل بينما يكون موجز الفريق قد تم عرضه بالفعل، مما يؤدي إلى تجربة مستخدم أفضل بكثير.
- العرض الشرطي: يمكنك أن تقرر برمجيًا أي الفتحات سيتم عرضها بناءً على شروط معينة، مثل حالة توثيق المستخدم أو الأذونات.
- التنقل الفرعي: يمكن التنقل في كل فتحة بشكل مستقل دون التأثير على الفتحات الأخرى. هذا مثالي للواجهات ذات علامات التبويب أو لوحات التحكم حيث تكون حالة لوحة واحدة منفصلة تمامًا عن الأخرى.
سيناريو واقعي: بناء لوحة تحكم معقدة
دعنا نصمم لوحة تحكم على عنوان URL /dashboard
. ستحتوي على منطقة محتوى رئيسية، ولوحة لنشاط الفريق، ولوحة لتحليلات الأداء.
بنية الملفات:
app/
└── dashboard/
├── @analytics/
│ ├── page.js // واجهة المستخدم لفتحة التحليلات
│ └── loading.js // واجهة مستخدم تحميل خاصة بالتحليلات
├── @team/
│ └── page.js // واجهة المستخدم لفتحة الفريق
├── layout.js // التخطيط الذي ينسق الفتحات
└── page.js // الفتحة الضمنية 'children' (المحتوى الرئيسي)
1. تخطيط لوحة التحكم (app/dashboard/layout.js
)
يستقبل هذا التخطيط ويرتب الفتحات الثلاث.
// app/dashboard/layout.js
export default function DashboardLayout({ children, analytics, team }) {
const isLoggedIn = true; // استبدل بمنطق توثيق حقيقي
return isLoggedIn ? (
<div>
<h1>لوحة التحكم الرئيسية</h1>
{children}
<div style={{ marginTop: '20px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px' }}>
<div style={{ border: '1px solid blue', padding: '10px' }}>
<h2>نشاط الفريق</h2>
{team}
</div>
<div style={{ border: '1px solid green', padding: '10px' }}>
<h2>تحليلات الأداء</h2>
{analytics}
</div>
</div>
</div>
) : (
<div>يرجى تسجيل الدخول لعرض لوحة التحكم.</div>
);
}
2. صفحات الفتحات (مثل، app/dashboard/@analytics/page.js
)
يحتوي ملف `page.js` لكل فتحة على واجهة المستخدم لتلك اللوحة المحددة.
// app/dashboard/@analytics/page.js
async function getAnalyticsData() {
// محاكاة طلب شبكة
await new Promise(resolve => setTimeout(resolve, 3000));
return { views: '1.2 مليون', revenue: '50,000 دولار' };
}
export default async function AnalyticsPage() {
const data = await getAnalyticsData();
return (
<div>
<p>مشاهدات الصفحة: {data.views}</p>
<p>الإيرادات: {data.revenue}</p>
</div>
);
}
// app/dashboard/@analytics/loading.js
export default function Loading() {
return <p>جاري تحميل بيانات التحليلات...</p>;
}
مع هذا الإعداد، عندما ينتقل المستخدم إلى /dashboard
، سيعرض Next.js `DashboardLayout`. سيتلقى التخطيط المحتوى المعروض من dashboard/page.js
و dashboard/@team/page.js
و dashboard/@analytics/page.js
كخصائص ويضعها وفقًا لذلك. والأهم من ذلك، أن لوحة التحليلات ستعرض حالة loading.js
الخاصة بها لمدة 3 ثوانٍ دون حظر عرض بقية لوحة التحكم.
التعامل مع المسارات غير المتطابقة باستخدام `default.js`
يطرح سؤال حاسم: ماذا يحدث إذا لم يتمكن Next.js من استرداد الحالة النشطة لفتحة لعنوان URL الحالي؟ على سبيل المثال، أثناء التحميل الأولي أو إعادة تحميل الصفحة، قد يكون عنوان URL هو /dashboard
، والذي لا يوفر تعليمات محددة لما يجب عرضه داخل فتحات @team
أو @analytics
. بشكل افتراضي، سيعرض Next.js خطأ 404.
لمنع ذلك، يمكننا توفير واجهة مستخدم احتياطية عن طريق إنشاء ملف default.js
داخل المسار المتوازي.
مثال:
// app/dashboard/@analytics/default.js
export default function DefaultAnalyticsPage() {
return (
<div>
<p>لم يتم تحديد بيانات تحليلات.</p>
</div>
);
}
الآن، إذا كانت فتحة التحليلات غير متطابقة، فسيعرض Next.js محتوى `default.js` بدلاً من صفحة 404. هذا ضروري لإنشاء تجربة مستخدم سلسة، خاصة عند التحميل الأولي لإعداد مسار متوازي معقد.
دمج مجموعات المسارات والمسارات المتوازية لبنى معمارية متقدمة
تتحقق القوة الحقيقية لموجّه التطبيقات عندما تجمع بين ميزاته. تعمل مجموعات المسارات والمسارات المتوازية معًا بشكل جميل لإنشاء بنى تطبيقات متطورة ومنظمة للغاية.
حالة استخدام: عارض محتوى متعدد الوسائط
تخيل منصة مثل معرض وسائط أو عارض مستندات حيث يمكن للمستخدم عرض عنصر ولكن يمكنه أيضًا فتح نافذة مشروطة (modal) لرؤية تفاصيله دون فقدان سياق الصفحة الخلفية. يطلق على هذا غالبًا اسم "المسارات المتقاطعة" (Intercepting Route) وهو نمط قوي مبني على المسارات المتوازية.
دعنا ننشئ معرض صور. عند النقر فوق صورة، يتم فتحها في نافذة مشروطة. ولكن إذا قمت بتحديث الصفحة أو الانتقال إلى عنوان URL الخاص بالصورة مباشرة، فيجب أن تظهر صفحة مخصصة لتلك الصورة.
بنية الملفات:
app/
├── @modal/(..)(..)photos/[id]/page.js // المسار المتقاطع للنافذة المشروطة
├── photos/
│ └── [id]/
│ └── page.js // صفحة الصورة المخصصة
├── layout.js // التخطيط الجذري الذي يستقبل فتحة @modal
└── page.js // صفحة المعرض الرئيسية
الشرح:
- ننشئ فتحة مسار متوازي باسم `@modal`.
- يستخدم المسار الغريب
(..)(..)photos/[id]
اصطلاحًا يسمى "مقاطع الالتقاط الشامل" لمطابقة مسار `photos/[id]` من مستويين أعلى (من الجذر). - عندما ينتقل المستخدم من صفحة المعرض الرئيسية (`/`) إلى صورة، يعترض Next.js هذا التنقل ويعرض صفحة النافذة المشروطة داخل فتحة `@modal` بدلاً من إجراء تنقل كامل للصفحة.
- تظل صفحة المعرض الرئيسية مرئية في خاصية `children` للتخطيط.
- إذا زار المستخدم مباشرةً `/photos/123`، فلن يتم تشغيل الاعتراض، وسيتم عرض الصفحة المخصصة في `photos/[id]/page.js` بشكل طبيعي.
يجمع هذا النمط بين المسارات المتوازية (فتحة `@modal`) واصطلاحات التوجيه المتقدمة لإنشاء تجربة مستخدم سلسة كان تنفيذها يدويًا معقدًا للغاية.
أفضل الممارسات والأخطاء الشائعة
أفضل الممارسات لمجموعات المسارات
- استخدم أسماء وصفية: اختر أسماء ذات معنى مثل
(auth)
أو(marketing)
أو(protected)
لجعل بنية مشروعك موثقة ذاتيًا. - اجعلها مسطحة حيثما أمكن: تجنب التداخل المفرط لمجموعات المسارات. عادة ما تكون البنية المسطحة أسهل في الفهم والصيانة.
- تذكر الغرض منها: استخدمها لتقسيم التخطيط والتنظيم، وليس لإنشاء أجزاء URL.
أفضل الممارسات للمسارات المتوازية
- دائمًا قم بتوفير `default.js`: لأي استخدام غير بسيط للمسارات المتوازية، قم بتضمين ملف `default.js` للتعامل مع التحميلات الأولية والحالات غير المتطابقة برشاقة.
- استفد من حالات التحميل الدقيقة: ضع ملف `loading.js` داخل دليل كل فتحة لتوفير ملاحظات فورية للمستخدم ومنع شلالات واجهة المستخدم.
- استخدمها لواجهة المستخدم المستقلة: تتألق المسارات المتوازية عندما يكون محتوى كل فتحة مستقلاً حقًا. إذا كانت اللوحات مترابطة بعمق، فقد يكون تمرير الخصائص لأسفل عبر شجرة مكون واحد حلاً أبسط.
الأخطاء الشائعة التي يجب تجنبها
- نسيان الاصطلاحات: خطأ شائع هو نسيان الأقواس `()` لمجموعات المسارات أو علامة `@` لفتحات المسارات المتوازية. سيؤدي هذا إلى معاملتها كأجزاء URL عادية.
- عدم وجود `default.js`: المشكلة الأكثر شيوعًا مع المسارات المتوازية هي رؤية أخطاء 404 غير متوقعة لأنه لم يتم توفير ملف `default.js` احتياطي للفتحات غير المتطابقة.
- سوء فهم `children`: في تخطيط يستخدم المسارات المتوازية، تذكر أن `children` هي مجرد واحدة من الفتحات، يتم تعيينها ضمنيًا إلى `page.js` أو التخطيط المتداخل في نفس الدليل.
الخاتمة: بناء مستقبل تطبيقات الويب
يوفر موجّه التطبيقات في Next.js، بميزات مثل مجموعات المسارات والمسارات المتوازية، أساسًا قويًا وقابلًا للتطوير لتطوير الويب الحديث. تقدم مجموعات المسارات حلاً أنيقًا لتنظيم الكود وتطبيق تخطيطات مميزة دون المساس بدلالات URL. تطلق المسارات المتوازية القدرة على بناء واجهات ديناميكية متعددة الأجزاء بحالات مستقلة، وهو أمر لم يكن يمكن تحقيقه في السابق إلا من خلال إدارة الحالة المعقدة من جانب العميل.
من خلال فهم هذه الأنماط المعمارية القوية والجمع بينها، يمكنك تجاوز مواقع الويب البسيطة والبدء في بناء تطبيقات متطورة وعالية الأداء وقابلة للصيانة تلبي متطلبات مستخدمي اليوم. قد يكون منحنى التعلم أكثر حدة من موجّه الصفحات الكلاسيكي، لكن العائد من حيث بنية التطبيق وتجربة المستخدم هائل. ابدأ في تجربة هذه المفاهيم في مشروعك التالي وأطلق العنان للإمكانات الكاملة لـ Next.js.