Next.js
أول تطبيق Next.js لك — من الصفحة إلى المكون 2026
📅 2026-11-12⏱ 8 دقائق قراءة
في المقال السابق، أعددنا بيئة العمل وأنشأنا مشروع Next.js. الآن سنبني **أول تطبيق حقيقي** ونفهم كيف يعمل Next.js.
في هذا الدليل العملي، سنأخذك خطوة بخطوة لبناء تطبيق Next.js كامل، مع تمارين وحلول.
## الفرق بين Next.js و React
**في React:**
- **صفحة واحدة** في `index.html`.
- **React Router** للتنقل.
- **إعدادات معقدة** (Vite, Webpack).
**في Next.js:**
- **عدة صفحات** تلقائياً.
- **App Router** مدمج.
- **إعدادات جاهزة**.
## نظام الملفات هو الراوتر
**أهم مبدأ في Next.js:** **نظام الملفات هو الراوتر**.
<table>
<thead>
<tr>
<th>الملف</th>
<th>الرابط</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>app/page.tsx</code></td>
<td><code>/</code></td>
</tr>
<tr>
<td><code>app/about/page.tsx</code></td>
<td><code>/about</code></td>
</tr>
<tr>
<td><code>app/blog/page.tsx</code></td>
<td><code>/blog</code></td>
</tr>
<tr>
<td><code>app/blog/[slug]/page.tsx</code></td>
<td><code>/blog/post-1</code></td>
</tr>
<tr>
<td><code>app/(marketing)/contact/page.tsx</code></td>
<td><code>/contact</code></td>
</tr>
</tbody>
</table>
**الفائدة:** لا تحتاج تعريف مسارات، فقط **أنشئ ملفات**.
## أول صفحة Next.js
### الخطوة 1: أنشئ صفحة "من نحن"
1. أنشئ مجلد `about` داخل `app/`.
2. أنشئ ملف `page.tsx` بداخله.
**`app/about/page.tsx`:**
```tsx
export default function AboutPage() {
return (
<main className="min-h-screen p-8">
<h1 className="text-4xl font-bold text-gray-900 mb-4">
من نحن
</h1>
<p className="text-lg text-gray-700">
نحن فريق عربي متخصص في تعليم البرمجة.
</p>
</main>
);
}
```
**احفظ الملف.**
**النتيجة:** افتح `http://localhost:3000/about` — سترى الصفحة!
**🎉 مبروك! أنشأت أول صفحة Next.js!**
### الخطوة 2: أنشئ صفحة "اتصل بنا"
**`app/contact/page.tsx`:**
```tsx
export default function ContactPage() {
return (
<main className="min-h-screen p-8">
<h1 className="text-4xl font-bold text-gray-900 mb-4">
اتصل بنا
</h1>
<p className="text-lg text-gray-700">
البريد: [email protected]
</p>
</main>
);
}
```
**احفظ الملف.**
**النتيجة:** `http://localhost:3000/contact` — يعمل!
## التنقل بين الصفحات (Link)
في React، نستخدم `<a>` أو `<Link>` من React Router. في Next.js، نستخدم `<Link>` من `next/link`.
### الخطوة 1: أنشئ Header
**`app/components/Header.tsx`:**
```tsx
import Link from "next/link";
export default function Header() {
return (
<header className="bg-white shadow-sm">
<nav className="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
<Link href="/" className="text-2xl font-bold text-blue-600">
موقعي
</Link>
<ul className="flex gap-6">
<li>
<Link href="/" className="text-gray-700 hover:text-blue-600">
الرئيسية
</Link>
</li>
<li>
<Link href="/about" className="text-gray-700 hover:text-blue-600">
من نحن
</Link>
</li>
<li>
<Link href="/contact" className="text-gray-700 hover:text-blue-600">
اتصل بنا
</Link>
</li>
</ul>
</nav>
</header>
);
}
```
### الخطوة 2: استخدمه في `layout.tsx`
**`app/layout.tsx`:**
```tsx
import type { Metadata } from "next";
import { Cairo } from "next/font/google";
import Header from "./components/Header";
import "./globals.css";
const cairo = Cairo({
subsets: ["arabic", "latin"],
weight: ["400", "600", "700", "900"],
});
export const metadata: Metadata = {
title: "موقعي",
description: "تطبيقي الأول بـ Next.js",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ar" dir="rtl">
<body className={cairo.className}>
<Header />
{children}
</body>
</html>
);
}
```
**النتيجة:** الهيدر يظهر في **كل الصفحات** تلقائياً!
## فهم Layout
**Layout** هو **تخطيط مشترك** بين عدة صفحات.
<table>
<thead>
<tr>
<th>الملف</th>
<th>الوظيفة</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>app/layout.tsx</code></td>
<td>التخطيط الجذري (لكل الصفحات)</td>
</tr>
<tr>
<td><code>app/about/layout.tsx</code></td>
<td>تخطيط لصفحات /about</td>
</tr>
<tr>
<td><code>app/blog/layout.tsx</code></td>
<td>تخطيط لصفحات /blog</td>
</tr>
</tbody>
</table>
**⚠️ مهم:** `layout.tsx` الجذري **إلزامي** ويحتوي على `<html>` و `<body>`.
## Server Components vs Client Components
**Next.js 15** يستخدم **Server Components** افتراضياً.
<table>
<thead>
<tr>
<th>المعيار</th>
<th>Server Component</th>
<th>Client Component</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>الافتراضي</strong></td>
<td>✅</td>
<td>❌ يحتاج "use client"</td>
</tr>
<tr>
<td><strong>useState</strong></td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td><strong>useEffect</strong></td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td><strong>onClick</strong></td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td><strong>async/await</strong></td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td><strong>الأداء</strong></td>
<td>✅ أسرع</td>
<td>⚠️ أبطأ</td>
</tr>
</tbody>
</table>
### مثال: Server Component
**`app/posts/page.tsx`:**
```tsx
async function getPosts() {
return [
{ id: 1, title: "مقال 1" },
{ id: 2, title: "مقال 2" },
];
}
export default async function PostsPage() {
const posts = await getPosts();
return (
<main className="p-8">
<h1 className="text-3xl font-bold mb-4">المقالات</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</main>
);
}
```
**⚠️ لاحظ:** `async` مباشرة — لا `useEffect`!
### مثال: Client Component
**`app/counter/page.tsx`:**
```tsx
"use client";
import { useState } from "react";
export default function CounterPage() {
const [count, setCount] = useState(0);
return (
<main className="p-8 text-center">
<h1 className="text-4xl font-bold mb-4">العدد: {count}</h1>
<button
onClick={() => setCount(count + 1)}
className="bg-blue-600 text-white px-6 py-3 rounded-lg"
>
+1
</button>
</main>
);
}
```
**⚠️ لاحظ:** `"use client"` في الأعلى.
## المكونات (Components)
**Next.js لا يفرض مكاناً للمكونات.** لكن الأفضل:
```
app/
├── components/ # مكونات عامة
│ ├── Header.tsx
│ └── Button.tsx
├── (marketing)/ # مجموعة صفحات
│ ├── about/
│ └── contact/
```
### مثال: Button Component
**`app/components/Button.tsx`:**
```tsx
interface ButtonProps {
children: React.ReactNode;
variant?: "primary" | "secondary";
onClick?: () => void;
}
export default function Button({
children,
variant = "primary",
onClick,
}: ButtonProps) {
const styles = {
primary: "bg-blue-600 text-white hover:bg-blue-700",
secondary: "bg-gray-200 text-gray-800 hover:bg-gray-300",
};
return (
<button
onClick={onClick}
className={`px-6 py-3 rounded-lg font-semibold transition ${styles[variant]}`}
>
{children}
</button>
);
}
```
## مثال عملي: موقع بسيط
### 1. الصفحة الرئيسية `app/page.tsx`
```tsx
import Link from "next/link";
export default function HomePage() {
return (
<main className="min-h-screen bg-gradient-to-br from-blue-500 to-purple-600 text-white flex items-center justify-center">
<div className="text-center">
<h1 className="text-5xl font-bold mb-4">
مرحباً بك في موقعي
</h1>
<p className="text-xl mb-8 opacity-90">
أول تطبيق Next.js لي
</p>
<Link
href="/about"
className="inline-block bg-white text-blue-600 px-8 py-3 rounded-lg font-bold hover:bg-gray-100 transition"
>
تعرف عليّ →
</Link>
</div>
</main>
);
}
```
### 2. صفحة من نحن `app/about/page.tsx`
```tsx
import Link from "next/link";
export default function AboutPage() {
return (
<main className="min-h-screen bg-gray-50 p-8">
<div className="max-w-3xl mx-auto">
<Link href="/" className="text-blue-600 hover:underline mb-8 inline-block">
← العودة للرئيسية
</Link>
<h1 className="text-4xl font-bold text-gray-900 mb-6">
من أنا
</h1>
<p className="text-lg text-gray-700 leading-relaxed mb-6">
أنا مطور ويب، أتعلم Next.js. هذا موقعي الأول.
</p>
<h2 className="text-2xl font-bold text-gray-900 mb-4">
مهاراتي
</h2>
<ul className="space-y-2 text-gray-700">
<li>✅ HTML & CSS</li>
<li>✅ JavaScript</li>
<li>✅ React</li>
<li>✅ Next.js</li>
</ul>
</div>
</main>
);
}
```
**🎉 مبروك! لديك موقع Next.js كامل!**
## تمارين عملية
### تمرين 1: صفحة "خدماتنا"
أنشئ صفحة `/services`.
**الحل:**
```tsx
// app/services/page.tsx
export default function ServicesPage() {
return (
<main className="p-8">
<h1 className="text-4xl font-bold mb-4">خدماتنا</h1>
<ul>
<li>تصميم مواقع</li>
<li>تطوير تطبيقات</li>
<li>استشارات تقنية</li>
</ul>
</main>
);
}
```
### تمرين 2: Header مع روابط
أضف روابط للخدمات والمدونة في Header.
**الحل:**
```tsx
<li><Link href="/services">خدماتنا</Link></li>
<li><Link href="/blog">المدونة</Link></li>
```
### تمرين 3: صفحة 404 مخصصة
أنشئ صفحة `app/not-found.tsx`.
**الحل:**
```tsx
import Link from "next/link";
export default function NotFound() {
return (
<main className="min-h-screen flex items-center justify-center">
<div className="text-center">
<h1 className="text-6xl font-bold text-gray-900 mb-4">404</h1>
<p className="text-xl text-gray-600 mb-8">الصفحة غير موجودة</p>
<Link href="/" className="text-blue-600 hover:underline">
العودة للرئيسية
</Link>
</div>
</main>
);
}
```
### تمرين 4: بطاقات
أنشئ قائمة بطاقات في الصفحة الرئيسية.
**الحل:**
```tsx
const features = [
{ icon: "⚡", title: "سريع", description: "أداء عالٍ" },
{ icon: "🎨", title: "جميل", description: "تصميم عصري" },
{ icon: "🚀", title: "سهل", description: "تطوير سريع" },
];
// في JSX
<div className="grid md:grid-cols-3 gap-6 mt-12">
{features.map((f) => (
<div key={f.title} className="bg-white p-6 rounded-xl shadow-sm">
<span className="text-4xl">{f.icon}</span>
<h3 className="text-xl font-bold mt-4">{f.title}</h3>
<p className="text-gray-600">{f.description}</p>
</div>
))}
</div>
```
### تمرين 5: Client Component
أنشئ صفحة عداد.
**الحل:**
```tsx
"use client";
import { useState } from "react";
export default function CounterPage() {
const [count, setCount] = useState(0);
return (
<main className="p-8 text-center">
<h1 className="text-4xl font-bold">{count}</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
</main>
);
}
```
### تمرين 6: Server Component مع بيانات
أنشئ صفحة تعرض قائمة من بيانات.
**الحل:**
```tsx
async function getUsers() {
return [
{ id: 1, name: "أحمد" },
{ id: 2, name: "محمد" },
];
}
export default async function UsersPage() {
const users = await getUsers();
return (
<ul>
{users.map((u) => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
```
### تمرين 7: Layout مخصص
أنشئ Layout لصفحات `/blog`.
**الحل:**
```tsx
// app/blog/layout.tsx
export default function BlogLayout({ children }: { children: React.ReactNode }) {
return (
<div className="max-w-4xl mx-auto p-8">
<aside className="mb-8 p-4 bg-gray-100 rounded-lg">
📚 مدونتي
</aside>
{children}
</div>
);
}
```
### تمرين 8: موقع كامل
اجمع كل ما تعلمته في موقع كامل.
**الحل:** (راجع المثال العملي أعلاه)
## حل المشاكل الشائعة
### 🔴 المشكلة 1: "useState is not defined"
**السبب:** استخدمت `useState` في Server Component.
**الحل:** أضف `"use client"` في الأعلى.
### 🔴 المشكلة 2: الصفحة لا تظهر
**السبب:** اسم الملف خاطئ (يجب أن يكون `page.tsx`).
**الحل:** تأكد من أن الملف اسمه `page.tsx` بالضبط.
### 🔴 المشكلة 3: Link لا يعمل
**السبب:** نسيت الاستيراد.
**الحل:**
```tsx
import Link from "next/link";
```
### 🔴 المشكلة 4: Layout لا يظهر
**السبب:** `children` مفقود.
**الحل:**
```tsx
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<Header />
{children} {/* ← مهم */}
</>
);
}
```
### 🔴 المشكلة 5: Hot Reload لا يعمل
**الحل:**
```bash
rmdir /s /q .next
npm run dev
```
## جدول أنواع الملفات
<table>
<thead>
<tr>
<th>الملف</th>
<th>الوظيفة</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>page.tsx</code></td>
<td>صفحة (URL)</td>
</tr>
<tr>
<td><code>layout.tsx</code></td>
<td>تخطيط مشترك</td>
</tr>
<tr>
<td><code>loading.tsx</code></td>
<td>شاشة التحميل</td>
</tr>
<tr>
<td><code>error.tsx</code></td>
<td>معالج الأخطاء</td>
</tr>
<tr>
<td><code>not-found.tsx</code></td>
<td>صفحة 404</td>
</tr>
<tr>
<td><code>route.ts</code></td>
<td>API Endpoint</td>
</tr>
<tr>
<td><code>template.tsx</code></td>
<td>قالب (مثل layout لكن يُعاد)</td>
</tr>
</tbody>
</table>
## قائمة تحقق نهائية
<table>
<thead>
<tr>
<th>المهمة</th>
<th>الحالة</th>
</tr>
</thead>
<tbody>
<tr>
<td>إنشاء صفحة "من نحن"</td>
<td>⬜</td>
</tr>
<tr>
<td>إنشاء صفحة "اتصل بنا"</td>
<td>⬜</td>
</tr>
<tr>
<td>إنشاء Header مع Link</td>
<td>⬜</td>
</tr>
<tr>
<td>فهم Layout</td>
<td>⬜</td>
</tr>
<tr>
<td>Server vs Client Components</td>
<td>⬜</td>
</tr>
<tr>
<td>إنشاء 404 مخصصة</td>
<td>⬜</td>
</tr>
<tr>
<td>حل التمارين الثمانية</td>
<td>⬜</td>
</tr>
</tbody>
</table>
## ماذا بعد هذا المقال؟
الآن بعد أن أتقنت الأساسيات، أنت جاهز للمقال التالي:
1. **App Router** — التنقل المتقدم.
2. **Server Components** — تعمق.
3. **Data Fetching** — جلب البيانات.
## الخلاصة
في هذا المقال، تعلمت:
- ✅ الفرق بين Next.js و React.
- ✅ نظام الملفات هو الراوتر.
- ✅ إنشاء الصفحات.
- ✅ التنقل بـ Link.
- ✅ Layouts.
- ✅ Server Components vs Client Components.
- ✅ 404 مخصصة.
- ✅ حل 8 تمارين عملية.
**تذكر:** Next.js يجعل بناء تطبيقات React **أسهل وأسرع**.