نظام الصفحات Routing في Next.js خطوة بخطوة
عندما تبدأ العمل مع Next.js، قد تظن أن التوجيه Routing مجرد انتقال من صفحة إلى صفحة، لكن الحقيقة أعمق من ذلك بكثير. نظام الصفحات في Next.js هو العمود الفقري الذي يحدد كيف يفهم التطبيق مساراته، كيف يعرض الواجهات، كيف يحمّل المحتوى، وكيف يحافظ على تجربة المستخدم سلسة حتى عندما يصبح المشروع كبيرًا ومعقدًا. الجميل في Next.js أنه يجعل هذه العملية طبيعية جدًا عبر التوجيه المعتمد على نظام الملفات، أي أنك لا تحتاج إلى كتابة خريطة معقدة للمسارات في أغلب الحالات، بل يكفي أن تنظم ملفاتك ومجلداتك بشكل ذكي، وسيقوم الإطار ببناء المسارات تلقائيًا. وهذا الأسلوب موجود في كل من App Router وPages Router، مع كون App Router هو المسار الأحدث والمُوصى به في التوثيق الرسمي حاليًا، بينما Pages Router ما زال مدعومًا وموجودًا للمشاريع القديمة أو لمن يفضّل بنية معينة.
ما هو Routing أصلًا، ولماذا يهمنا في Next.js؟
Routing ببساطة هو الآلية التي تربط عنوان URL بالمحتوى الذي يراه المستخدم. عندما يكتب الزائر /about، يجب على التطبيق أن يعرف: هل أُظهر صفحة "من نحن"؟ هل أُحمّل بيانات من الخادم؟ هل أستخدم نفس التخطيط Layout مع تغيير المحتوى فقط؟ هنا تظهر قوة Next.js، لأنه لا يكتفي بعرض صفحة مرتبطة بمسار، بل ينسّق بين العرض من جهة الخادم والواجهة من جهة العميل، ويقدّم تحسينات مثل prefetching والتبديل السلس بين الصفحات، بحيث لا يشعر المستخدم أنه ينتقل بين صفحات ويب تقليدية بطيئة، بل يعيش تجربة أقرب إلى تطبيق حديث وسريع. توثيق Next.js يوضح أن التنقل في App Router يستفيد من التحميل المسبق، والتدفق Streaming، والانتقال على مستوى العميل، وهذا جزء أساسي من فلسفة الإطار كله.
الصورة الكبيرة: App Router وPages Router
من المهم جدًا أن نفهم أن Next.js اليوم يملك طريقتين للتوجيه. الأولى هي App Router، وهي الأحدث وتدعم ميزات React الحديثة مثل Server Components، وهي الموصى بها في التوثيق الرسمي. الثانية هي Pages Router، وهي الطريقة الأصلية التي استخدمها Next.js لسنوات وما زالت مدعومة، خصوصًا في المشاريع الموجودة بالفعل. الفكرة هنا ليست أن أحدهما "خاطئ" والآخر "صحيح"، بل أن App Router هو التطور الطبيعي الذي يقدم مرونة أكبر في التخطيط، والتنقل، وتجربة البيانات، بينما Pages Router ما زال ممتازًا في كثير من السيناريوهات التقليدية. معرفة الفرق بينهما تساعدك على قراءة أي مشروع Next.js تقريبًا، لأنك ستفهم بسرعة من أين تأتي المسارات وكيف تُبنى.
كيف يعمل التوجيه المعتمد على الملفات في App Router؟
في App Router، يعتمد Next.js على بنية مجلد app، وكل ملف page.js أو page.tsx داخل هذا المسار يمثل صفحة فعلية في التطبيق. مثلًا، app/page.tsx يمثل الصفحة الرئيسية، وapp/about/page.tsx يمثل المسار /about. هذا الأسلوب يختصر الكثير من الإعداد اليدوي، ويجعل التنظيم البصري للمجلدات يتوافق مباشرة مع بنية الموقع. توثيق Next.js يشرح أن المسارات تُبنى من خلال الملفات والمجلدات، وأن layout.js وpage.js هما من الملفات الأساسية في هذا النظام.
مثال بسيط جدًا
// app/page.tsx
export default function HomePage() {
return <h1>الصفحة الرئيسية</h1>;
}
// app/about/page.tsx
export default function AboutPage() {
return <h1>من نحن</h1>;
}
بهذا الترتيب، لن تحتاج إلى تعريف route configuration معقدة. يكفي أن يكون الملف موجودًا في المكان الصحيح حتى يصبح المسار جاهزًا. هذه البساطة هي أحد الأسباب التي تجعل Next.js محبوبًا جدًا لدى المطورين، خصوصًا عندما يبدؤون مشروعًا صغيرًا ثم يكبر تدريجيًا.
لماذا layout.js مهم جدًا؟
إذا كانت page.js هي المحتوى المتغيّر من مسار إلى آخر، فإن layout.js هو الإطار الثابت الذي يحيط بهذا المحتوى. في App Router، يُستخدم Layout للحفاظ على أجزاء مشتركة من الواجهة مثل الشريط العلوي، القائمة الجانبية، أو الفوتر، بحيث لا يعاد بناؤها بالكامل عند الانتقال بين الصفحات. هذا لا يحسّن الأداء فقط، بل يحافظ على الاتساق البصري ويمنح المستخدم إحساسًا بأن التطبيق متماسك. Next.js يقدّم Layouts كجزء أساسي من بنية App Router، ويشرح أنها ترتبط مباشرة ببنية الملفات
// app/layout.tsx
import type { ReactNode } from 'react';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="ar">
<body>
<header>شريط علوي ثابت</header>
<main>{children}</main>
<footer>حقوق النشر</footer>
</body>
</html>
);
}
هذا المثال يوضح فكرة مهمة جدًا: الصفحة ليست كل شيء، بل هي مجرد جزء داخل Layout أكبر. وعندما تفهم هذا، ستبدأ في تصميم تطبيقاتك بطريقة أكثر نضجًا، لأنك لن تكرر نفس العناصر في كل صفحة.
التنقل بين الصفحات: <Link> أفضل من أي شيء آخر في معظم الحالات
Next.js يوصي باستخدام مكوّن <Link> للتنقل بين الصفحات بدل الاعتماد على التنقل اليدوي كل مرة. لماذا؟ لأن Link يستفيد من تحسينات داخلية مثل prefetching، ويجعل الانتقال أسرع وأكثر سلاسة، خاصة عندما يكون الرابط مرئيًا على الشاشة أو عندما يتوقع Next.js أن المستخدم قد يزور الصفحة التالية. في App Router، توثيق Next.js يصرّح بوضوح أن <Link> هو الخيار المفضل للتنقل، وأن useRouter يُستخدم عندما تحتاج إلى انتقال برمجي أو سلوك خاص.
import Link from 'next/link';
export default function Navbar() {
return (
<nav>
<Link href="/">الرئيسية</Link>
<Link href="/about">من نحن</Link>
<Link href="/contact">تواصل معنا</Link>
</nav>
);
}
الفرق العملي هنا كبير. عندما تبني موقعًا فيه عشرات الروابط، استخدام Link في كل مكان يمنح المستخدم تجربة أفضل، ويخفف عليك أنت أيضًا من إدارة التنقلات يدويًا. وهذا من تلك التفاصيل الصغيرة التي تصنع فرقًا كبيرًا في المشاريع الحقيقية.
متى نستخدم useRouter؟
في App Router، يمكن استخدام useRouter داخل Client Components فقط لتنفيذ تنقل برمجي. هذا مفيد عندما تضغط زرًا في نموذج، أو تحتاج إلى إعادة التوجيه بعد تسجيل الدخول، أو تريد الانتقال إلى صفحة معينة بعد نجاح عملية ما. أما في Pages Router، فهناك أيضًا useRouter من next/router، وهو يوفّر الوصول إلى كائن router داخل مكوّنات React الكلاسيكية. التوثيق الرسمي يوضح أن useRouter في App Router يأتي من next/navigation، بينما Pages Router يستخدم next/router.
'use client';
import { useRouter } from 'next/navigation';
export default function LoginButton() {
const router = useRouter();
const handleLogin = async () => {
// بعد نجاح تسجيل الدخول
router.push('/dashboard');
};
return <button onClick={handleLogin}>تسجيل الدخول</button>;
}
هنا الفكرة ليست فقط "اذهب إلى صفحة أخرى"، بل "اتخذ قرارًا برمجيًا بناءً على حدث أو نتيجة". وهذه نقطة محورية في التطبيقات الحديثة، لأن التنقل لم يعد مجرد نقر على رابط، بل قد يكون نتيجة عملية، شرط، أو حالة داخل التطبيق.
المسارات الديناميكية: عندما لا تعرف قيمة الرابط مسبقًا
من أمتع أجزاء Routing في Next.js هي المسارات الديناميكية. تخيل أنك تبني مدونة، وكل مقالة لها slug مختلف مثل /blog/nextjs-routing أو /blog/react-hooks. بدلاً من إنشاء ملف لكل مقال، يمكنك إنشاء مسار ديناميكي واحد يتعامل مع أي قيمة تأتي في عنوان URL. في Pages Router وApp Router معًا، الفكرة الأساسية هي وضع اسم داخل أقواس مربعة مثل [id] أو [slug]. التوثيق الرسمي يشرح أن Dynamic Segments تُستخدم عندما لا تعرف أسماء المقاطع مسبقًا، وأنها تُملأ وقت الطلب أو تُحضّر وقت البناء بحسب طريقة العرض.
مثال في App Router
// app/blog/[slug]/page.tsx
type Props = {
params: Promise<{ slug: string }>;
};
export default async function BlogPostPage({ params }: Props) {
const { slug } = await params;
return (
<article>
<h1>مقال: {slug}</h1>
<p>هنا سيتم عرض محتوى المقال المرتبط بهذا الـ slug.</p>
</article>
);
}
مثال في Pages Router
// pages/blog/[slug].tsx
import { useRouter } from 'next/router';
export default function BlogPostPage() {
const router = useRouter();
const { slug } = router.query;
return (
<article>
<h1>مقال: {slug}</h1>
</article>
);
}
المعنى العملي هنا عميق جدًا: تستطيع بناء آلاف الصفحات من قالب واحد فقط. وهذا مثالي للمتاجر، المدونات، أنظمة إدارة المحتوى، واللوحات الإدارية.
المسارات المتداخلة: التنظيم الذي ينقذك عندما يكبر المشروع
واحدة من أجمل نقاط القوة في App Router هي المسارات المتداخلة، حيث يمكنك بناء صفحات داخلية تحت Layoutات داخلية، وكل ذلك بنظام ملفات واضح جدًا. هذا الأسلوب مناسب جدًا عندما يكون لديك لوحة تحكم فيها أقسام كثيرة مثل المستخدمين، الإعدادات، التقارير، المنتجات، وغيرها. بدل أن تكرر الشريط الجانبي في كل صفحة، تضعه في Layout فرعي، وتترك المحتوى يتغير فقط. Next.js يقدّم هذا كمفهوم أساسي في App Router، والوثائق تشرح كيف تُستخدم المجلدات والملفات لبناء صفحات وتخطيطات متداخلة.
app/
dashboard/
layout.tsx
page.tsx
settings/
page.tsx
users/
page.tsx
في هذا المثال، يمكنك جعل /dashboard يحتوي على Layout خاص، ثم تتفرع منه صفحات مثل /dashboard/settings و/dashboard/users. هذا يقلل التكرار بشكل هائل، ويجعل الصيانة أسهل بكثير عندما يبدأ الفريق في التوسع.
Route Groups: تنظيم ذكي بلا تأثير على الرابط
أحيانًا تحتاج إلى تنظيم الملفات في مجلدات لأسباب تنظيمية، لكنك لا تريد لهذه المجلدات أن تظهر في عنوان URL. هنا تأتي Route Groups في App Router. التوثيق الرسمي يوضح أن Route Groups تُكتب داخل أقواس دائرية مثل (folderName)، وأنها تُستخدم لتنظيم المسارات حسب الفريق أو الغرض أو البنية، من دون أن تؤثر على المسار النهائي في الرابط. هذه ميزة تبدو صغيرة، لكنها مذهلة عندما تعمل على مشروع كبير أو متعدد الأقسام.
app/
(marketing)/
page.tsx
about/
page.tsx
(dashboard)/
page.tsx
settings/
page.tsx
هنا، المجلدات بين الأقواس تساعدك على الفصل المنطقي بين أقسام المشروع، لكن الرابط نفسه يظل نظيفًا وواضحًا. هذه من تلك التفاصيل التي تجعل Next.js مناسبًا جدًا للفرق التي تهتم ببنية المشروع بقدر اهتمامها بالوظيفة نفسها.
Parallel Routes وIntercepting Routes: عندما تصبح الواجهة أكثر ذكاءً
لو أنك تبني لوحة تحكم كبيرة أو تجربة تشبه التطبيقات الاحترافية المعقدة، فربما ستحتاج إلى عرض أكثر من جزء من الواجهة في الوقت نفسه، أو فتح نافذة منبثقة modal فوق الصفحة الحالية مع الحفاظ على الرابط قابلًا للمشاركة. Next.js يدعم هذا النوع من السيناريوهات عبر Parallel Routes وIntercepting Routes. التوثيق الرسمي يذكر بوضوح أن هذه الميزات يمكن استخدامها معًا لبناء modals تدعم deep linking، مع الحفاظ على السياق عند إعادة التحميل، وإمكانية الرجوع للخلف بدل تغيير كامل للمسار.
هذا المستوى من التوجيه لا يتعلق فقط بعرض صفحة، بل بتصميم تجربة تفاعلية أكثر نضجًا. تخيّل أن المستخدم يفتح منتجًا داخل modal، ثم يشارك الرابط، فيفتح المنتج نفسه مباشرة في نفس السياق. هذا النوع من المرونة كان يحتاج في السابق إلى حلول يدوية كثيرة، أما الآن فNext.js يوفّر بنية واضحة له.
صفحات الحالة الخاصة: loading وerror وnot-found
من الأمور الجميلة في App Router أنك لا تتعامل فقط مع الصفحة الناجحة، بل أيضًا مع حالات التحميل والخطأ والصفحات غير الموجودة بطريقة منظمة داخل نفس بنية الملفات. التوثيق يذكر ملفات خاصة مثل loading.js وerror.js وnot-found.js، وهي مفيدة جدًا عندما تريد أن تكون تجربة المستخدم لطيفة حتى في الظروف غير المثالية. في الواقع، كثير من التطبيقات تبدو ممتازة في الحالة العادية، لكنها تنهار بصريًا عند أول خطأ. Next.js يحاول معالجة هذا عبر هذه الملفات الخاصة.
// app/products/loading.tsx
export default function Loading() {
return <p>جارٍ تحميل المنتجات...</p>;
}
// app/products/not-found.tsx
export default function NotFound() {
return <p>هذه الصفحة غير موجودة.</p>;
}
وجود هذه الملفات يجعل التطبيق أكثر إنسانية، لأن المستخدم لا يبقى أمام شاشة فارغة أو رسالة تقنية جافة. بدل ذلك، يحصل على تغذية راجعة مفهومة، وهذا فرق كبير في جودة المنتج النهائي.
Pages Router: ما زال مهمًا ومفيدًا جدًا
رغم أن App Router هو المستقبل الذي تدفع نحوه Next.js، فإن Pages Router ما زال في اللعبة، وما زال مستخدمًا في مشاريع كثيرة جدًا. التوثيق الرسمي يصفه بأنه الراوتر الأصلي، ويشير إلى أنه لا يزال مدعومًا ومُحسّنًا، مع توصية بالمهاجرة إلى App Router للاستفادة من الميزات الأحدث. Pages Router يعتمد أيضًا على نظام الملفات، بحيث يمثل كل ملف داخل pages مسارًا في التطبيق. هذا يجعله سهل التعلم وسهل الفهم، خصوصًا إذا كنت بدأت مع Next.js قبل ظهور App Router.
مثال سريع في Pages Router
// pages/index.tsx
export default function Home() {
return <h1>الصفحة الرئيسية</h1>;
}
// pages/about.tsx
export default function About() {
return <h1>من نحن</h1>;
}
ورغم أن البنية تبدو مباشرة جدًا، إلا أن Pages Router يحتوي أيضًا على قدرات قوية مثل dynamic routes وAPI routes وuseRouter التقليدي. لذلك لا ينبغي أن تنظر إليه على أنه قديم بمعنى "غير مفيد"، بل على أنه بنية مستقرة وراسخة لا تزال تخدم كثيرًا من المشاريع.
كيف أفكر في Routing أثناء بناء مشروع حقيقي؟
أفضل طريقة لفهم Routing في Next.js ليست حفظ المصطلحات، بل تخيّل المشروع كخريطة مدينة. الصفحة الرئيسية هي الساحة الكبيرة، الأقسام الأساسية هي الشوارع الرئيسية، والصفحات الداخلية هي الأزقة والمباني المتفرعة. App Router يشبه التخطيط الحضري المنظم الذي يضع لك اللوحات والإشارات تلقائيًا، بينما صفحات المشروع هي الأماكن التي يقصدها المستخدم. عندما تبدأ بالتفكير بهذه الطريقة، ستدرك أن Routing ليس مجرد "ملف يساوي صفحة"، بل هو طريقة لتصميم السلوك، التسلسل، والحالة البصرية للتطبيق كله. وهذا الفهم يوفّر عليك الكثير من الفوضى لاحقًا، خصوصًا عندما يتضاعف عدد الصفحات والميزات.
أفضل الممارسات التي تجعل Routing نظيفًا ومريحًا
هناك عدة عادات بسيطة لكنها مؤثرة جدًا. أولها أن تحافظ على هيكل مجلدات واضح، لأن نظام الملفات في Next.js هو اللغة التي يتحدث بها التطبيق. ثانيها أن تستخدم Layouts للأجزاء المشتركة بدل تكرارها في كل صفحة. ثالثها أن تعتمد <Link> للتنقل الأساسي، وأن تستخدم useRouter فقط حين تحتاج إلى تحكم برمجي فعلي. رابعها أن تفصل بين الصفحات العامة واللوحات الإدارية أو المسارات الخاصة باستخدام Route Groups عندما يكبر المشروع. وخامسها أن تستفيد من الملفات الخاصة للحالات غير المثالية بدل ترك المستخدم في فراغ بصري. هذه التوجيهات ليست مجرد ذوق شخصي، بل هي منسجمة مباشرة مع فلسفة Next.js نفسها كما تعرضها الوثائق الرسمية.
مثال عملي: هيكل مشروع متوازن
app/
layout.tsx
page.tsx
about/
page.tsx
blog/
[slug]/
page.tsx
dashboard/
layout.tsx
page.tsx
settings/
page.tsx
(marketing)/
contact/
page.tsx
هذا المثال يجمع بين صفحة رئيسية، وصفحة ثابتة، ومسار ديناميكي، ولوحة تحكم بخط تخطيطي خاص، ومجموعة تسويقية منظمة لا تؤثر على الـ URL. عند قراءة هذا الهيكل، يجب أن تشعر أن المشروع "مفهوه" بصريًا قبل حتى أن تفتح أي ملف. هذا هو الهدف الحقيقي من Routing الجيد: أن يكون واضحًا لك وللفريق ولأي شخص سينضم إلى المشروع بعدك.
أخطاء شائعة يقع فيها المطورون
من الأخطاء المتكررة أن يخلط المطور بين App Router وPages Router داخل نفس الذهنية من دون أن ينتبه لاختلاف الأدوات والملفات الخاصة بكل منهما. خطأ شائع آخر هو استخدام useRouter في App Router من الاستيراد القديم next/router بدل next/navigation. كذلك، كثيرون يكررون العناصر المشتركة في كل صفحة بدل استخدام Layout، أو يبنون مسارات ديناميكية من دون التفكير في حالة التحميل أو عدم وجود البيانات. وهناك أيضًا من يترك بنية المجلدات تتضخم بشكل عشوائي، ثم يجد نفسه غارقًا في ملفات يصعب تتبعها. هذه مشاكل تنظيمية أكثر منها تقنية، لكن تأثيرها كبير جدًا على عمر المشروع وسهولة تطويره.
لماذا يبدو Next.js قويًا في التوجيه مقارنةً بإطارات أخرى؟
السبب ليس فقط أن لديه ملفات وخاصية routing، بل لأنه دمج التوجيه مع فلسفة كاملة في الأداء والتنظيم وتجربة المستخدم. Next.js يربط المسار بالصفحة، الصفحة بالـ Layout، Layout بسياق العرض، وسلوك التنقل بالتحسينات مثل prefetching والتبديل على مستوى العميل. كذلك، App Router يضيف أدوات متقدمة مثل route groups وparallel routes وintercepting routes، ما يسمح ببناء واجهات أكثر تعقيدًا من دون أن تتحول البنية إلى فوضى. لهذا يشعر كثير من المطورين أن Next.js لا يقدّم "routing" فقط، بل يقدّم طريقة تفكير كاملة لبناء التطبيق.
خاتمة
فهم نظام الصفحات Routing في Next.js ليس درسًا جانبيًا، بل هو أحد أهم المفاتيح التي تفتح لك الباب لفهم الإطار كله. عندما تستوعب كيف تُبنى المسارات من الملفات، وكيف تعمل Layouts، ومتى تستخدم Link، ومتى تحتاج إلى useRouter، وكيف تتعامل مع dynamic routes والحالات الخاصة، ستبدأ مشاريعك تأخذ شكلًا أنظف وأكثر احترافية. والأجمل من ذلك أن Next.js لا يجبرك على التعقيد من البداية؛ بل يقدّم لك بساطة الملف والمجلد، ثم يفتح أمامك أبوابًا متقدمة عندما تحتاجها فعلًا. هذا التدرج هو ما يجعل التعلّم ممتعًا، ويجعل التطوير في الحياة الواقعية أقل توترًا وأكثر انسجامًا. وإذا كان هناك درس واحد يستحق أن يبقى في الذهن، فهو أن Routing في Next.js ليس مجرد انتقال بين صفحات، بل هو طريقة كاملة لتنظيم التجربة الرقمية من أول نقرة إلى آخر لحظة داخل التطبيق.