Next.js📅 2026-11-12⏱ 8 دقائق قراءة⚡ مقال 2 من 10

أول تطبيق Next.js لك — من الصفحة إلى المكون 2026

دليل عملي مفصل لبناء أول تطبيق Next.js — الصفحات، المكونات، التخطيطات، والتنقل، مع تمارين وحلول

في المقال السابق، أعددنا بيئة العمل وأنشأنا مشروع Next.js. الآن سنبني أول تطبيق حقيقي ونفهم كيف يعمل Next.js.

في هذا الدليل العملي، سنأخذك خطوة بخطوة لبناء تطبيق Next.js كامل، مع تمارين وحلول.

الفرق بين Next.js و React

في React:

  • صفحة واحدة في index.html.
  • React Router للتنقل.
  • إعدادات معقدة (Vite, Webpack).

في Next.js:

  • عدة صفحات تلقائياً.
  • App Router مدمج.
  • إعدادات جاهزة.

نظام الملفات هو الراوتر

أهم مبدأ في Next.js: نظام الملفات هو الراوتر.

الملفالرابط
app/page.tsx/
app/about/page.tsx/about
app/blog/page.tsx/blog
app/blog/[slug]/page.tsx/blog/post-1
app/(marketing)/contact/page.tsx/contact

الفائدة: لا تحتاج تعريف مسارات، فقط أنشئ ملفات.

أول صفحة Next.js

الخطوة 1: أنشئ صفحة "من نحن"

  1. أنشئ مجلد about داخل app/.
  2. أنشئ ملف page.tsx بداخله.

app/about/page.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:

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:

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:

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 هو تخطيط مشترك بين عدة صفحات.

الملفالوظيفة
app/layout.tsxالتخطيط الجذري (لكل الصفحات)
app/about/layout.tsxتخطيط لصفحات /about
app/blog/layout.tsxتخطيط لصفحات /blog

⚠️ مهم: layout.tsx الجذري إلزامي ويحتوي على <html> و <body>.

Server Components vs Client Components

Next.js 15 يستخدم Server Components افتراضياً.

المعيارServer ComponentClient Component
الافتراضي✅❌ يحتاج "use client"
useState❌✅
useEffect❌✅
onClick❌✅
async/await✅❌
الأداء✅ أسرع⚠️ أبطأ

مثال: Server Component

app/posts/page.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:

"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:

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

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

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.

الحل:

// 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.

الحل:

<li><Link href="/services">خدماتنا</Link></li>
<li><Link href="/blog">المدونة</Link></li>

تمرين 3: صفحة 404 مخصصة

أنشئ صفحة app/not-found.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: بطاقات

أنشئ قائمة بطاقات في الصفحة الرئيسية.

الحل:

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

أنشئ صفحة عداد.

الحل:

"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 مع بيانات

أنشئ صفحة تعرض قائمة من بيانات.

الحل:

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.

الحل:

// 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 لا يعمل

السبب: نسيت الاستيراد.

الحل:

import Link from "next/link";

🔴 المشكلة 4: Layout لا يظهر

السبب: children مفقود.

الحل:

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <>
      <Header />
      {children}  {/* ← مهم */}
    </>
  );
}

🔴 المشكلة 5: Hot Reload لا يعمل

الحل:

rmdir /s /q .next
npm run dev

جدول أنواع الملفات

الملفالوظيفة
page.tsxصفحة (URL)
layout.tsxتخطيط مشترك
loading.tsxشاشة التحميل
error.tsxمعالج الأخطاء
not-found.tsxصفحة 404
route.tsAPI Endpoint
template.tsxقالب (مثل layout لكن يُعاد)

قائمة تحقق نهائية

المهمةالحالة
إنشاء صفحة "من نحن"⬜
إنشاء صفحة "اتصل بنا"⬜
إنشاء Header مع Link⬜
فهم Layout⬜
Server vs Client Components⬜
إنشاء 404 مخصصة⬜
حل التمارين الثمانية⬜

ماذا بعد هذا المقال؟

الآن بعد أن أتقنت الأساسيات، أنت جاهز للمقال التالي:

  1. App Router — التنقل المتقدم.
  2. Server Components — تعمق.
  3. Data Fetching — جلب البيانات.

الخلاصة

في هذا المقال، تعلمت:

  • ✅ الفرق بين Next.js و React.
  • ✅ نظام الملفات هو الراوتر.
  • ✅ إنشاء الصفحات.
  • ✅ التنقل بـ Link.
  • ✅ Layouts.
  • ✅ Server Components vs Client Components.
  • ✅ 404 مخصصة.
  • ✅ حل 8 تمارين عملية.

تذكر: Next.js يجعل بناء تطبيقات React أسهل وأسرع.

📚 مقالات ذات صلة

Next.js

مشروع Next.js متكامل — مدونة احترافية 2026

مشروع عملي شامل لبناء مدونة كاملة بـ Next.js — مع Markdown، SEO، نشر تلقائي، وتصميم احترافي

Next.js

نشر تطبيق Next.js — دليل شامل 2026

دليل عملي مفصل لنشر تطبيق Next.js — Vercel، Firebase، Netlify، والتصدير الثابت

Next.js

المصادقة في Next.js — دليل شامل 2026

دليل عملي مفصل للمصادقة في Next.js — NextAuth.js، JWT، Middleware، وحماية المسارات