almessadi.
العودة إلى الفهرس

مكونات خادم React مقابل SSR: أين تكون الحدود فعليًا_

تحل كل من SSR ومكونات خادم React مشكلات مرتبطة، لكنها ليست نفس الآلية. يساعد فهم الحدود في حجم الحزمة، وتدفق البيانات، والهندسة المعمارية.

تاريخ النشر20 مارس 2024
وقت القراءة10 min read

تعد مكونات خادم React والتقديم من جانب الخادم سهلة الخلط مع بعضها البعض لأنها تُستخدم غالبًا في نفس التطبيق.

إنها مرتبطة. لكنها ليست الشيء نفسه.

إذا تعاملت معها كأنها قابلة للتبادل، ستجد نفسك مع قرارات معمارية مربكة وشفرة برمجية تشحن المزيد من JavaScript على العميل أكثر مما تحتاجه.

## يحل SSR مشكلة التقديم الأولي

يقوم SSR التقليدي بتقديم HTML على الخادم حتى يتمكن المتصفح من عرض شيء مفيد قبل أن يقوم تطبيق العميل بتجفيفه بالكامل.

هذا قيمة لـ:

- الطلاء الأول
- قابلية الزحف
- الأداء المدرك

لكن SSR لا يلغي الحاجة إلى JavaScript على العميل. إذا كانت الصفحة تفاعلية، لا يزال المتصفح يحتاج إلى الكود اللازم لتجفيف واجهة المستخدم تلك.

هذه هي النقطة الأساسية التي تفوتها العديد من الفرق: HTML المقدم من الخادم ليس هو نفس الشيء كتنفيذ المكونات من جانب الخادم فقط.

## مكونات الخادم تحل مشكلة موضع الحزمة

تغير مكونات خادم React المكان الذي يُسمح فيه ببعض منطق المكونات بالعيش.

تشغل مكون خادم على الخادم، ويمكن الوصول إلى الموارد من جانب الخادم مباشرة، ولا تشحن تنفيذها الخاص إلى المتصفح.

هذا يجعلها مفيدة لـ:

- تجميع واجهة المستخدم المدعومة بقاعدة بيانات
- تحويل المحتوى المكلف
- إبقاء التبعيات الخاصة بالخادم بعيدًا عن حزمة العميل

مثال بسيط:

```tsx
import { db } from "@/lib/db";
import MarkdownIt from "markdown-it";

const md = new MarkdownIt();

export default async function PostBody({ slug }: { slug: string }) {
  const post = await db.post.findUniqueOrThrow({ where: { slug } });
  const html = md.render(post.body);

  return <article dangerouslySetInnerHTML={{ __html: html }} />;
}

إذا بقيت هذه مكون خادم، فلن يحتاج المتصفح إلى عميل قاعدة البيانات أو محلل Markdown فقط لجعل بقية الصفحة تفاعلية.

لا يزال التجفيف موجودًا

لا تلغي مكونات الخادم مكونات العميل. إنها تسمح لك باستخدامها بشكل أكثر تعمدًا.

في اللحظة التي تحتاج فيها إلى واجهات برمجة التطبيقات الخاصة بالمتصفح، أو الحالة المحلية، أو معالجات الأحداث، تدخل إلى مجال العميل:

"use client";

import { useState } from "react";

export function LikeButton() {
  const [liked, setLiked] = useState(false);

  return (
    <button onClick={() => setLiked((value) => !value)}>
      {liked ? "أعجبني" : "أعجبني"}
    </button>
  );
}

لا يزال يتم تجفيف هذا المكون على العميل. الهدف ليس "عدم وجود JavaScript في كل مكان". الهدف هو شحن JavaScript فقط حيث يحتاج المتصفح إليه فعليًا.

القرار المعماري

السؤال العملي ليس "هل يجب أن نستخدم SSR أم RSC؟" في تطبيقات Next.js الحديثة، غالبًا ما تستخدم كلاهما.

السؤال الأفضل هو:

"أي أجزاء من هذه الشجرة تحتاج إلى العمل في المتصفح؟"

إذا كانت الإجابة "قليلة جدًا"، يمكن لمكونات الخادم تقليل حجم الحزمة وانتشار التبعيات بشكل جوهري.

إذا كانت معظم الصفحة تفاعلية للغاية، لا تزال مكونات الخادم تساعد في الوصول إلى البيانات والتركيب، لكنها لا تحول سحريًا لوحة تحكم تفاعلية إلى صفحة من جانب الخادم فقط.

ما الذي يسوء في حقول الشفرة الحقيقية

أنماط الفشل المشتركة يمكن التنبؤ بها:

  • وضع علامة على مسارات كاملة بـ "use client" لأن ورقة واحدة تحتاج إلى التفاعلية
  • تمرير كائنات كبيرة متسلسلة عبر الحدود بين الخادم/العميل
  • استيراد وحدات خاصة بالخادم إلى شفرة العميل عن طريق الخطأ
  • افتراض أن مكونات الخادم تحل محل جميع حدود واجهة برمجة التطبيقات

الانضباط هو إبقاء الحدود ضيقة.

استخدم مكونات الخادم لـ:

  • جلب البيانات
  • المكتبات الخاصة بالخادم فقط
  • تجميع المحتوى غير التفاعلي

استخدم مكونات العميل لـ:

  • معالجة الأحداث
  • واجهات برمجة التطبيقات الخاصة بالمتصفح فقط
  • حالة التفاعل المحلية

هذا الانقسام ليس أيديولوجيًا. إنه فقط أسهل للتوسع.

قراءة إضافية