Kodokon kodokon.com

React الحديث: Server Components و use و useTransition و useOptimistic

استكشف مكوّنات الخادم، وقراءة الوعود بواسطة use، والتحديثات التفاؤلية في React 19.

11 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

React Server Components (RSC) تعيد رسم الحدّ بين العميل والخادم. مكوّن الخادم يُشغَّل على الخادم فقط: شيفرته لا تصل أبداً إلى حزمة العميل، ويمكن أن يكون async، ويقرأ قاعدة البيانات أو نظام الملفات مباشرةً، ويُرسَل ناتجه إلى المتصفّح كـ دفق مُسلسَل (حمولة RSC) يدمجه React مع شجرة العميل. في المقابل، لا يملك حالة، ولا تأثيرات، ولا وصولاً إلى المتصفّح: لا useState، ولا useEffect، ولا معالِجات أحداث. وهو لا يُعاد عرضه أبداً على العميل.

JSX
// Server component: never sent to the client.
export default async function NotesPage() {
  const notes = await db.notes.findAll();
  return (
    <ul>
      {notes.map((note) => (
        <li key={note.id}>{note.title}</li>
      ))}
    </ul>
  );
}
مكوّن خادم غير متزامن يستعلم قاعدة البيانات مباشرةً.

تعيش التفاعلية في مكوّنات العميل، المميَّزة بموجِّه 'use client' في أعلى الملف. هذا الموجِّه لا يميّز "مكوّن عميل" بل حدّاً: كل ما تستورده تلك الوحدة ينتقل أيضاً إلى جانب العميل. الخصائص التي تعبر الحدّ يجب أن تكون قابلة للتسلسل: كائنات عادية، مصفوفات، وعود... لكن أبداً دوال عادية أو نُسَخ من أصناف.

JSX
'use client';

import { useState } from 'react';

export function LikeButton({ initialCount }) {
  const [count, setCount] = useState(initialCount);
  return (
    <button onClick={() => setCount(count + 1)}>
      {count} likes
    </button>
  );
}
موجِّه 'use client' يحدّد المنطقة التفاعلية.

يُدخِل React 19 الواجهة use، التي تقرأ قيمة وعد أو سياق. على خلاف الخطّافات، يمكن استدعاء use داخل شرط أو حلقة. بالنظر إلى وعد، يُعلّق المكوّن حتى الحلّ، معتمداً على أقرب حدّ Suspense. النمط الاصطلاحي: مكوّن خادم يُنشئ الوعد من دون انتظاره، ويمرّره كخاصية، ومكوّن عميل يستهلكه بواسطة use: يبدأ الخادم بدفق الصفحة من دون انتظار البيانات.

JSX
import { use, Suspense } from 'react';

function Comments({ commentsPromise }) {
  const comments = use(commentsPromise);
  return comments.map((c) => (
    <p key={c.id}>{c.text}</p>
  ));
}

function Page({ commentsPromise }) {
  return (
    <Suspense fallback={<Spinner />}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  );
}
use يُعلّق المكوّن حتى يُحَلّ الوعد.

على جانب التفاعل، يُعلِّم useTransition التحديث بأنه غير ملحّ ويكشف isPending كي تعرض مؤشّراً خفيفاً من دون حجب الإدخال. ويُكمِل useOptimistic الثنائي في تحويرات الشبكة: تعرض فوراً الحالة المأمولة بينما يجري إجراء غير متزامن؛ وعند انتهاء الإجراء (نجاحاً أو فشلاً)، يُسقِط React القيمة التفاؤلية ويعرض من جديد الحالة الحقيقية، تلك التي تأتي من مصدر الحقيقة.

JSX
const [optimisticLikes, addOptimisticLike] =
  useOptimistic(likes, (count, delta) => count + delta);

function handleLike() {
  startTransition(async () => {
    addOptimisticLike(1);
    await saveLike();
    // At the end, React shows the real state again.
  });
}
الواجهة تتفاعل فوراً، والخادم يؤكّد بعد ذلك.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. ما الذي لا يستطيع مكوّن الخادم فعله؟
    • أن يُعلَن غير متزامن وينتظر طلباً
    • أن يقرأ قاعدة البيانات مباشرةً
    • أن يستعمل useState ومعالِجات الأحداث
    • أن يعرض مكوّنات عميل كأبناء
  2. أيّ قاعدة من قواعد الخطّافات يُسمَح للواجهة use بخرقها؟
    • أن تُستدعى خارج مكوّن
    • أن تُستدعى داخل شرط أو حلقة
    • أن تُستدعى بعد عودة مبكّرة من الوحدة
    • أن تُستدعى داخل صنف
  3. ماذا يحدث لقيمة useOptimistic حين ينتهي الإجراء غير المتزامن؟
    • تصبح الحالة الدائمة للمكوّن
    • تُسقَط وتعود الحالة الحقيقية إلى التولّي
    • تُدمَج مع الحالة الحقيقية
    • تبقى حتى العرض اليدوي التالي