React والأطر البرمجية الحديثة للواجهات الأمامية

مكونات الخادم وبنية Next.js

4 دقيقة للقراءة

تمثل مكونات خادم React (RSC) أكبر تحول معماري في React منذ الخطافات. فهم هذا النموذج يُختبر بشكل متزايد في المقابلات، خاصة في الشركات التي تستخدم Next.js. مكونات الخادم مستقرة في React 19، و App Router هو الافتراضي في Next.js 15 (الذي صدر في أكتوبر 2024) و Next.js 16 (الإصدار الحالي في عام 2026).

النموذج الذهني لمكونات الخادم

لدى React الآن نوعان من المكونات:

مكونات الخادممكونات العميل
أين تعملالخادم فقطالخادم (SSR) + العميل (الترطيب)
يمكنها استخدامasync/await، قاعدة البيانات، fsuseState, useEffect, معالجات الأحداث
لا يمكنها استخدامالخطافات، واجهات المتصفح، معالجات الأحداثالوصول المباشر لقاعدة البيانات، fs
تأثير الحزمةصفر — الكود يبقى على الخادممُضمّن في حزمة JS
الافتراضي في App Routerنعم (افتراضي)يجب إضافة "use client"
// مكون الخادم (افتراضي في App Router) — لا حاجة لتوجيه
async function ProductPage({ params }) {
  // هذا الكود يعمل فقط على الخادم
  const product = await db.products.findById(params.id);

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      {/* مكون عميل للأجزاء التفاعلية */}
      <AddToCartButton productId={product.id} price={product.price} />
    </div>
  );
}

// مكون العميل — يجب أن يحتوي على توجيه "use client"
'use client';

import { useState } from 'react';

function AddToCartButton({ productId, price }) {
  const [added, setAdded] = useState(false);

  return (
    <button onClick={() => {
      addToCart(productId);
      setAdded(true);
    }}>
      {added ? 'تمت الإضافة!' : `أضف للسلة — $${price}`}
    </button>
  );
}

متى تستخدم كلاً منهما

أبقِ كمكون خادم عندما:

  • جلب البيانات من قاعدة بيانات أو API
  • الوصول لموارد الخلفية (نظام الملفات، متغيرات البيئة)
  • عرض محتوى ثابت أو نادر التحديث
  • المكون ليس لديه تفاعلية

حوّل لمكون عميل عندما:

  • استخدام خطافات React (useState, useEffect, useRef, إلخ)
  • إضافة معالجات أحداث (onClick, onChange, onSubmit)
  • استخدام واجهات المتصفح فقط (localStorage, window, navigator)
  • المكون يحتاج للاستجابة لتفاعل المستخدم

أفضل ممارسة: ادفع حدود "use client" لأسفل الشجرة قدر الإمكان. أبقِ تخطيطات الأب كمكونات خادم واجعل فقط المكونات الورقية التفاعلية على جانب العميل.

أنماط Next.js App Router

جلب البيانات

// مكون الخادم: الجلب مباشرة (لا حاجة لـ useEffect)
async function BlogPosts() {
  const posts = await fetch('https://api.example.com/posts', {
    next: { revalidate: 3600 } // ISR: إعادة التحقق كل ساعة
  }).then(r => r.json());

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

إجراءات الخادم

// إجراء الخادم: مُعرّف بـ "use server"
async function createPost(formData) {
  'use server';

  const title = formData.get('title');
  const content = formData.get('content');

  await db.posts.create({ title, content });
  revalidatePath('/posts');
}

// يُستخدم في نموذج (مكون خادم)
function NewPostForm() {
  return (
    <form action={createPost}>
      <input name="title" required />
      <textarea name="content" required />
      <button type="submit">إنشاء منشور</button>
    </form>
  );
}

Actions و useOptimistic و use() في React 19

أضفى React 19 طابعًا رسميًا على نمط "Actions" لإرسال النماذج وتعديلات البيانات. تتكامل Actions مع عنصر <form> ومع الخطافات الجديدة useActionState و useFormStatus و useOptimistic للتعامل مع حالات الانتظار والأخطاء وواجهة المستخدم المتفائلة دون كود إضافي زائد:

'use client';
import { useOptimistic, useFormStatus } from 'react';

function LikeButton({ likes, onLike }) {
  const [optimisticLikes, addOptimisticLike] = useOptimistic(
    likes,
    (current) => current + 1
  );
  return (
    <form action={async () => { addOptimisticLike(); await onLike(); }}>
      <SubmitButton count={optimisticLikes} />
    </form>
  );
}

function SubmitButton({ count }) {
  const { pending } = useFormStatus();
  return <button disabled={pending}>{pending ? '...' : `${count}`}</button>;
}

أصبح الخطاف use() مستقرًا في React 19، ويسمح لك بقراءة الـ Promise والـ Context مباشرة أثناء العرض، بما في ذلك داخل حدود Suspense. هذا يبسّط جلب البيانات في كل من مكونات الخادم والعميل.

بث SSR

import { Suspense } from 'react';

// الهيكل يُعرض فورًا، الأجزاء البطيئة تُبث تدريجيًا
async function Dashboard() {
  return (
    <div>
      <h1>لوحة التحكم</h1>

      {/* تُعرض فورًا */}
      <Suspense fallback={<Skeleton />}>
        {/* تُبث عند جاهزية البيانات */}
        <RevenueChart />
      </Suspense>

      <Suspense fallback={<Skeleton />}>
        <RecentOrders />
      </Suspense>
    </div>
  );
}

استراتيجيات العرض

الاستراتيجيةمتى يتحدث المحتوىحالة الاستخدام
SSG (ثابت)وقت البناء فقطصفحات التسويق، التوثيق
ISR (تدريجي)دوريًا (مؤقت إعادة التحقق)منشورات المدونة، صفحات المنتجات
SSR (ديناميكي)كل طلبمحتوى مخصص، بيانات فورية
جانب العميلبعد الترطيبميزات تفاعلية للغاية
// SSG: بدون خيارات fetch (افتراضي)
const data = await fetch('https://api.example.com/static');

// ISR: إعادة التحقق كل 60 ثانية
const data = await fetch('https://api.example.com/posts', {
  next: { revalidate: 60 }
});

// SSR: طازج في كل طلب
const data = await fetch('https://api.example.com/dashboard', {
  cache: 'no-store'
});

أسئلة المقابلات الشائعة

س: "هل يمكن لمكون الخادم استيراد مكون عميل؟" نعم. يمكن لمكونات الخادم عرض مكونات العميل كأبناء. يحتاج مكون العميل فقط لتوجيه "use client".

س: "هل يمكن لمكون العميل استيراد مكون خادم؟" ليس مباشرة. لكن يمكن لمكون العميل قبول مكونات الخادم كأبناء عبر نمط خاصية children.

س: "ماذا يحدث لكود مكون الخادم في المتصفح؟" لا شيء — لا يصل أبدًا للمتصفح. كود مكون الخادم غير مُضمّن في حزمة JavaScript. هذه هي فائدة الأداء الرئيسية.

نصيحة للمقابلات: القدرة على شرح حدود RSC — لماذا يعمل كود معين على الخادم مقابل العميل، وكيف تتدفق البيانات بينهما — هي عامل تمييز. معظم المرشحين يمكنهم استخدام الخطافات لكن قليلون يستطيعون توضيح النموذج المعماري.

الآن لنطبق ما تعلمته ببناء جدول بيانات قابل للبحث في المختبر التالي. :::

اختبار

الوحدة 3: React والأطر البرمجية الحديثة

خذ الاختبار
نشرة أسبوعية مجانية

ابقَ على مسار النيرد

بريد واحد أسبوعياً — دورات، مقالات معمّقة، أدوات، وتجارب ذكاء اصطناعي.

بدون إزعاج. إلغاء الاشتراك في أي وقت.