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"> البريد: contact@nahdaai.com </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 **أسهل وأسرع**.