App Router في Next.js — دليل شامل 2026
دليل عملي مفصل لـ App Router في Next.js — المسارات، المجموعات، المسارات الديناميكية، والتنقل المتقدم
في المقال السابق، بنيت أول تطبيق Next.js وتعلمت الأساسيات. الآن سنتعمق في App Router — وهو نظام التوجيه الحديث في Next.js 15.
في هذا الدليل العملي، سنأخذك خطوة بخطوة لفهم App Router بالكامل، مع تمارين وحلول.
ما هو App Router؟
App Router هو نظام التوجيه الجديد في Next.js (منذ الإصدار 13).
يعتمد على: نظام الملفات هو الراوتر.
| الملف | الرابط |
|---|---|
app/page.tsx | / |
app/about/page.tsx | /about |
app/blog/page.tsx | /blog |
app/blog/[slug]/page.tsx | /blog/any-post |
app/(shop)/cart/page.tsx | /cart |
app/dashboard/settings/page.tsx | /dashboard/settings |
أنواع الملفات في App Router
| الملف | الوظيفة |
|---|---|
page.tsx | صفحة (URL) |
layout.tsx | تخطيط مشترك |
loading.tsx | شاشة التحميل |
error.tsx | معالج الأخطاء |
not-found.tsx | صفحة 404 |
route.ts | API Endpoint |
template.tsx | قالب (يعاد عند التنقل) |
default.tsx | للمسارات المتوازية |
المسارات الأساسية
1. الصفحة الرئيسية
app/page.tsx → /
2. مسار عادي
app/about/page.tsx → /about
3. مسار متداخل
app/blog/tech/page.tsx → /blog/tech
4. مسار ديناميكي
app/blog/[slug]/page.tsx → /blog/أي-شيء
app/blog/[slug]/page.tsx:
export default function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
return <h1>المقال: {params.slug}</h1>;
}
⚠️ لاحظ: في Next.js 15، params هو Promise — يجب استخدام async/await.
5. مسار ديناميكي شامل
app/docs/[...slug]/page.tsx → /docs/a/b/c
export default async function Docs({
params,
}: {
params: Promise<{ slug: string[] }>;
}) {
const { slug } = await params;
return <h1>المسار: {slug.join("/")}</h1>;
}
6. مسار اختياري
app/shop/[[...slug]]/page.tsx → /shop أو /shop/a/b
مجموعات المسارات (Route Groups)
استخدم ( ) لتنظيم المسارات بدون التأثير على URL.
app/
├── (marketing)/
│ ├── about/
│ │ └── page.tsx → /about
│ └── contact/
│ └── page.tsx → /contact
├── (shop)/
│ ├── products/
│ │ └── page.tsx → /products
│ └── cart/
│ └── page.tsx → /cart
└── layout.tsx
الفائدة: تخطيط مختلف لكل مجموعة:
app/
├── (marketing)/
│ ├── layout.tsx # تخطيط التسويق
│ └── about/page.tsx
└── (shop)/
├── layout.tsx # تخطيط المتجر
└── cart/page.tsx
Layouts المتداخلة
app/
├── layout.tsx # التخطيط الجذري
├── page.tsx
└── dashboard/
├── layout.tsx # تخطيط لوحة التحكم
├── page.tsx
└── settings/
└── page.tsx
app/dashboard/layout.tsx:
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex">
<aside className="w-64 bg-gray-900 text-white p-4">
<nav>
<a href="/dashboard">لوحة التحكم</a>
<a href="/dashboard/settings">الإعدادات</a>
</nav>
</aside>
<main className="flex-1 p-8">{children}</main>
</div>
);
}
النتيجة: كل صفحات /dashboard/* ستحتوي على الشريط الجانبي.
Loading — شاشة التحميل
app/dashboard/loading.tsx:
export default function Loading() {
return (
<div className="flex items-center justify-center min-h-screen">
<div className="animate-spin rounded-full h-12 w-12 border-4 border-blue-600 border-t-transparent" />
</div>
);
}
النتيجة: عند تحميل أي صفحة في /dashboard، تظهر شاشة التحميل.
Error — معالج الأخطاء
app/dashboard/error.tsx:
"use client";
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div className="text-center p-8">
<h1 className="text-4xl font-bold text-red-600 mb-4">
❌ حدث خطأ
</h1>
<p className="text-gray-600 mb-6">{error.message}</p>
<button
onClick={reset}
className="bg-blue-600 text-white px-6 py-3 rounded-lg"
>
حاول مرة أخرى
</button>
</div>
);
}
⚠️ مهم: error.tsx يجب أن يكون Client Component ("use client").
Not Found — صفحة 404
app/not-found.tsx:
import Link from "next/link";
export default function NotFound() {
return (
<div className="min-h-screen flex items-center justify-center text-center">
<div>
<h1 className="text-9xl font-bold text-gray-900">404</h1>
<p className="text-2xl text-gray-600 mb-8">الصفحة غير موجودة</p>
<Link
href="/"
className="bg-blue-600 text-white px-8 py-3 rounded-lg"
>
العودة للرئيسية
</Link>
</div>
</div>
);
}
التنقل بين الصفحات
1. <Link> — الطريقة الأساسية
import Link from "next/link";
<Link href="/about">من نحن</Link>
2. useRouter — التنقل برمجياً
"use client";
import { useRouter } from "next/navigation";
export default function LoginButton() {
const router = useRouter();
const handleLogin = () => {
// ... منطق تسجيل الدخول
router.push("/dashboard");
};
return <button onClick={handleLogin}>تسجيل الدخول</button>;
}
3. redirect — إعادة التوجيه
import { redirect } from "next/navigation";
export default async function Page() {
const isLoggedIn = false;
if (!isLoggedIn) {
redirect("/login");
}
return <h1>مرحباً</h1>;
}
useRouter و usePathname
app/components/NavLink.tsx:
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
interface NavLinkProps {
href: string;
children: React.ReactNode;
}
export default function NavLink({ href, children }: NavLinkProps) {
const pathname = usePathname();
const isActive = pathname === href;
return (
<Link
href={href}
className={`px-4 py-2 rounded-lg transition ${
isActive
? "bg-blue-600 text-white"
: "text-gray-700 hover:bg-gray-100"
}`}
>
{children}
</Link>
);
}
generateStaticParams
للمسارات الديناميكية في التصدير الثابت:
export function generateStaticParams() {
const posts = [
{ slug: "post-1" },
{ slug: "post-2" },
];
return posts.map((post) => ({
slug: post.slug,
}));
}
مثال عملي: مدونة
1. الصفحة الرئيسية app/page.tsx
import Link from "next/link";
export default function HomePage() {
return (
<main className="p-8">
<h1 className="text-4xl font-bold mb-6">📝 مدونتي</h1>
<Link href="/blog" className="text-blue-600 hover:underline">
تصفح المقالات →
</Link>
</main>
);
}
2. قائمة المقالات app/blog/page.tsx
import Link from "next/link";
const posts = [
{ slug: "learn-nextjs", title: "تعلم Next.js" },
{ slug: "react-hooks", title: "React Hooks" },
{ slug: "typescript-tips", title: "نصائح TypeScript" },
];
export default function BlogPage() {
return (
<main className="p-8 max-w-4xl mx-auto">
<h1 className="text-4xl font-bold mb-8">المقالات</h1>
<ul className="space-y-4">
{posts.map((post) => (
<li key={post.slug}>
<Link
href={`/blog/${post.slug}`}
className="text-xl text-blue-600 hover:underline"
>
{post.title}
</Link>
</li>
))}
</ul>
</main>
);
}
3. المقال الفردي app/blog/[slug]/page.tsx
import Link from "next/link";
import { notFound } from "next/navigation";
const posts = {
"learn-nextjs": { title: "تعلم Next.js", content: "..." },
"react-hooks": { title: "React Hooks", content: "..." },
"typescript-tips": { title: "نصائح TypeScript", content: "..." },
};
export function generateStaticParams() {
return Object.keys(posts).map((slug) => ({ slug }));
}
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = posts[slug as keyof typeof posts];
if (!post) notFound();
return (
<main className="p-8 max-w-4xl mx-auto">
<Link href="/blog" className="text-blue-600 hover:underline mb-8 inline-block">
← العودة
</Link>
<h1 className="text-4xl font-bold mb-4">{post.title}</h1>
<p>{post.content}</p>
</main>
);
}
تمارين عملية
تمرين 1: 3 صفحات متداخلة
أنشئ /dashboard/profile و /dashboard/settings.
الحل:
app/dashboard/profile/page.tsx
app/dashboard/settings/page.tsx
تمرين 2: مسار ديناميكي
أنشئ /users/[id] يعرض ID المستخدم.
الحل:
export default async function UserPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
return <h1>المستخدم: {id}</h1>;
}
تمرين 3: Route Group
نظّم الصفحات في مجموعتين.
الحل:
app/(marketing)/about/page.tsx
app/(shop)/products/page.tsx
تمرين 4: Layout مخصص
أنشئ Layout للوحة التحكم.
الحل:
// app/dashboard/layout.tsx
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div className="flex">
<aside>Sidebar</aside>
<main>{children}</main>
</div>
);
}
تمرين 5: Loading
أضف شاشة تحميل.
الحل:
// app/loading.tsx
export default function Loading() {
return <div>جاري التحميل...</div>;
}
تمرين 6: Error
أضف معالج أخطاء.
الحل:
"use client";
export default function Error({ reset }: { reset: () => void }) {
return (
<div>
<h1>خطأ!</h1>
<button onClick={reset}>حاول مرة أخرى</button>
</div>
);
}
تمرين 7: NavLink نشط
أنشئ NavLink يظهر الرابط النشط.
الحل: (راجع NavLink.tsx أعلاه)
تمرين 8: مدونة كاملة
ابنِ مدونة بكل ما تعلمته.
الحل: (راجع المثال العملي أعلاه)
حل المشاكل الشائعة
🔴 المشكلة 1: params غير متاح مباشرة
السبب: في Next.js 15، params هو Promise.
الحل:
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
}
🔴 المشكلة 2: Link لا يعمل
السبب: نسيت الاستيراد.
الحل:
import Link from "next/link";
🔴 المشكلة 3: useRouter لا يعمل
السبب: لم تُضف "use client".
الحل: أضف في أعلى الملف.
🔴 المشكلة 4: generateStaticParams مفقود
السبب: مع output: 'export'، تحتاج تعريف كل المسارات.
الحل:
export function generateStaticParams() {
return [{ slug: "post-1" }, { slug: "post-2" }];
}
🔴 المشكلة 5: 404 في الإنتاج
السبب: السيرفر لا يعرف المسارات.
الحل: أضف rewrites في firebase.json.
جدول الملفات الخاصة
| الملف | الوظيفة | ملاحظة |
|---|---|---|
page.tsx | صفحة | مطلوب للعرض |
layout.tsx | تخطيط | لا يُعاد عند التنقل |
template.tsx | قالب | يُعاد عند التنقل |
loading.tsx | تحميل | يظهر أثناء التحميل |
error.tsx | خطأ | Client Component |
not-found.tsx | 404 | عند عدم وجود الصفحة |
route.ts | API | لا يعرض UI |
قائمة تحقق نهائية
| المهمة | الحالة |
|---|---|
| فهم نظام الملفات هو الراوتر | ⬜ |
| إنشاء مسارات متداخلة | ⬜ |
| المسارات الديناميكية | ⬜ |
| Route Groups | ⬜ |
| Layouts المتداخلة | ⬜ |
| Loading و Error | ⬜ |
| حل التمارين الثمانية | ⬜ |
ماذا بعد هذا المقال؟
الآن بعد أن أتقنت App Router، أنت جاهز للمقال التالي:
- Server Components — تعمق.
- Data Fetching — جلب البيانات.
- API Routes — بناء APIs.
الخلاصة
في هذا المقال، تعلمت:
- ✅ ما هو App Router.
- ✅ نظام الملفات هو الراوتر.
- ✅ المسارات الديناميكية.
- ✅ Route Groups.
- ✅ Layouts المتداخلة.
- ✅ Loading و Error.
- ✅ التنقل بين الصفحات.
- ✅ حل 8 تمارين عملية.
تذكر: App Router هو المستقبل — أتقنه جيداً.
أول تطبيق Next.js لك — من الصفحة إلى المكون 2026
Server Components في Next.js — دليل شامل 2026
📚 مقالات ذات صلة
مشروع Next.js متكامل — مدونة احترافية 2026
مشروع عملي شامل لبناء مدونة كاملة بـ Next.js — مع Markdown، SEO، نشر تلقائي، وتصميم احترافي
نشر تطبيق Next.js — دليل شامل 2026
دليل عملي مفصل لنشر تطبيق Next.js — Vercel، Firebase، Netlify، والتصدير الثابت
المصادقة في Next.js — دليل شامل 2026
دليل عملي مفصل للمصادقة في Next.js — NextAuth.js، JWT، Middleware، وحماية المسارات