ahmad hasanzadeh branding logoahmad hasanzadeh branding logo
    خانهپروژه هامقالاتدرباره منتکنولوژی هاارتباط با من
ahmad hasanzadeh branding logoahmad hasanzadeh branding logo

ممنون که سر زدی ッ

© ۱۴۰۵

احمد حسن زاده. تمامی حقوق محفوظ است.

React Server Components (RSC) چیست؟ راهنمای مفهومی کامل

React Server Components (RSC) چیست؟ راهنمای مفهومی کامل

توضیح کامل React Server Components: چیستی، تفاوت با SSR، مرز بین Server و Client Component و نحوه‌ی کارکرد استریم.

اگر اسم React Server Components (که به اختصار RSC نامیده می‌شود) را شنیده‌اید و فکر کرده‌اید «این که همون Server-Side Rendering قدیمیه»، تنها نیستید. این یکی از رایج‌ترین برداشت‌های اشتباه در دنیای React است. RSC از React 19 به صورت پایدار (stable) عرضه شده و امروز به مدل پیش‌فرض رندر در بیشتر فریم‌ورک‌های مبتنی بر React تبدیل شده است. در این مقاله بدون وابسته کردن توضیحات به یک فریم‌ورک خاص، بررسی می‌کنیم که RSC واقعاً چیست، چطور کار می‌کند و مرز بین کامپوننت‌های سرور و کلاینت کجاست.

RSC واقعاً چیست؟

یک Server Component کامپوننتی است که فقط و فقط در سرور رندر می‌شود و کد آن هرگز به مرورگر ارسال نمی‌شود. همین نکته، تفاوت اصلی RSC با SSR سنتی است. در SSR، سرور برای بارگذاری اولیه صفحه، HTML تولید می‌کند، اما جاوااسکریپت همان کامپوننت هم برای انجام hydration به کلاینت فرستاده می‌شود. در RSC اما، منطق، importها و وابستگی‌های کامپوننت برای همیشه روی سرور باقی می‌مانند؛ کلاینت هرگز آن را دریافت، پارس یا اجرا نمی‌کند.

نتیجه این است که یک Server Component می‌تواند بدون نگرانی از حجم باندل، مستقیماً یک کلاینت دیتابیس را import کند، به متغیرهای محیطی حساس دسترسی داشته باشد یا از یک کتابخانه‌ی پردازشی سنگین استفاده کند؛ چون هیچ‌کدام از این‌ها وارد باندل جاوااسکریپت کلاینت نمی‌شوند. تنها چیزی که به کلاینت می‌رسد، «نتیجه‌ی» رندر آن کامپوننت است که به شکلی فشرده و قابل استریم سریالایز شده است.

تفاوت Client Component و Server Component

در یک اپلیکیشن مبتنی بر RSC، هر کامپوننت در یکی از این دو دسته قرار می‌گیرد:

  • Server Component (پیش‌فرض): روی سرور رندر می‌شود، به API‌های مرورگر دسترسی ندارد، نمی‌تواند از state یا افکت (useState، useEffect) استفاده کند، اما به منابع سمت سرور مستقیماً دسترسی دارد.
  • Client Component: با گذاشتن دستورالعمل "use client" در ابتدای فایل مشخص می‌شود، در مرورگر رندر می‌شود، از hookها و تعامل‌پذیری پشتیبانی می‌کند و مثل کامپوننت‌های سنتی React باندل و ارسال می‌شود.
  • نمودار نمایش مرز بین Server Component و Client Component در یک اپلیکیشن React

    قانونی که بیشتر از همه باعث سردرگمی می‌شود این است: یک Server Component می‌تواند یک Client Component را import و رندر کند، اما برعکسش امکان‌پذیر نیست. اگر یک Client Component به محتوای رندرشده در سرور نیاز داشته باشد، آن محتوا باید به‌عنوان prop (معمولاً از طریق children) به آن پاس داده شود. این محدودیت اتفاقی نیست؛ چون به‌محض عبور به قلمرو کلاینت، هر چیزی در ادامه‌ی آن باید چیزی باشد که مرورگر واقعاً بتواند اجرا کند.

    فرایند رندر و استریم چگونه کار می‌کند؟

    وقتی یک Server Component رندر می‌شود، React مستقیماً HTML تولید نمی‌کند. در عوض، یک توصیف سریالایزشده از درخت کامپوننت‌ها را با یک فرمت داخلی به نام پروتکل «Flight» می‌سازد. این payload مشخص می‌کند چه چیزی باید رندر شود و شامل ارجاع به Client Componentهایی است که باید hydrate شوند، اما هیچ‌کدام از کد منبع Server Component را در خود ندارد.

    سرور می‌تواند این payload را به‌صورت تکه‌تکه و هم‌زمان با آماده‌شدن داده‌ها استریم کند؛ به همین دلیل RSC به‌طور طبیعی با Suspense هماهنگ است. یک فراخوانی کند داده در یک Server Component، بقیه‌ی صفحه را بلاک نمی‌کند؛ کلاینت هر تکه را به محض رسیدن رندر می‌کند، نه لزوماً به ترتیب بالا به پایین.

    نمودار جریان استریم React Server Components از سرور به مرورگر

    اگر اپلیکیشن از SSR یا رندر استاتیک هم استفاده کند، همان payload برای تولید HTML واقعی در اولین نمایش صفحه استفاده می‌شود؛ یعنی کاربر محتوای معنادار را بلافاصله می‌بیند، حتی پیش از بارگذاری هر جاوااسکریپت سمت کلاینت.

    چه کارهایی داخل Server Component ممکن است و چه کارهایی ممکن نیست؟

    Server Componentها برای این موارد مناسب‌اند:

    • دریافت مستقیم داده از دیتابیس یا API داخلی، بدون نیاز به یک لایه‌ی API جداگانه
    • خواندن فایل‌ها، متغیرهای محیطی یا کلیدهای امنیتی سمت سرور، به‌صورت امن
    • رندر بخش‌های حجیم، استاتیک یا محتوامحور که هیچ‌گاه به تعامل‌پذیری نیاز ندارند

    اما این موارد در آن‌ها ممکن نیست:

    • استفاده از useState، useEffect، useContext یا هر hook دیگری که به رانتایم کلاینت وابسته است
    • دسترسی به APIهای مخصوص مرورگر مثل window، localStorage یا event listenerها
    • پاس دادن نمونه‌های کلاس، توابع یا شیء Date به‌عنوان prop به Client Component؛ این‌ها قابل سریالایز شدن روی مرز سرور/کلاینت نیستند و باعث خطای رانتایم می‌شوند
    ProductList.jsjsx
    // Server Component — بدون نیاز به دستورالعمل "use client"
    async function ProductList() {
      const products = await db.query('SELECT * FROM products');
     
      return (
        <ul>
          {products.map((product) => (
            <ProductCard key={product.id} product={product} />
          ))}
        </ul>
      );
    }

    توجه کنید که خود کامپوننت async است و مستقیماً داخل بدنه‌ی تابع منتظر داده می‌ماند؛ نه useEffectای در کار است، نه مدیریت دستی state لودینگ. این فقط به این دلیل ممکن است که این کامپوننت هرگز در مرورگر اجرا نمی‌شود.

    Server Functionها: فراخوانی سرور از کلاینت

    Client Componentها همچنان به راهی برای فعال‌سازی منطق سمت سرور نیاز دارند؛ مثل ارسال یک فرم یا تغییر یک رکورد در دیتابیس. این کار از طریق Server Function انجام می‌شود که با دستورالعمل "use server" تعریف می‌شود. یک Server Function می‌تواند داخل یک Server Component ساخته و به‌عنوان prop پاس داده شود، یا مستقیماً در یک Client Component ایمپورت شود. وقتی از یک المان تعاملی فراخوانی می‌شود، React یک درخواست به سرور می‌فرستد، تابع را اجرا می‌کند و نتیجه را برمی‌گرداند؛ بدون نیاز به نوشتن دستی یک API route.

    تا اواخر سال ۲۰۲۴ به این‌ها معمولاً «Server Action» گفته می‌شد. این اصطلاح الان مشخصاً به Server Functionی اشاره دارد که داخل یک prop به نام action یا در ارسال فرم استفاده می‌شود؛ یعنی هر Server Function لزوماً Server Action نیست، هرچند هر Server Action یک Server Function است.

    اشتباهات رایجی که باید از آن‌ها دوری کرد

    • از روی عادت همه چیز را "use client" علامت‌گذاری کردن. این کار بخش زیادی از هدف اصلی RSC را از بین می‌برد و در نهایت همان حجم جاوااسکریپتی را ارسال می‌کنید که قرار بود از آن دوری کنید. پیش‌فرض را روی Server Component بگذارید و فقط جایی که واقعاً به تعامل‌پذیری نیاز است، سراغ رندر کلاینت بروید.
    • پاس دادن propهای غیرقابل‌سریالایز از مرز سرور به کلاینت. توابع، نمونه‌های کلاس و شیء Date نمی‌توانند به‌عنوان prop از Server Component به Client Component عبور کنند.
    • فرض کردن اینکه propهای ارسال‌شده به Client Component خصوصی هستند. هر چیزی که از یک Server Component به یک Client Component پاس داده شود، در payload شبکه‌ای RSC قابل مشاهده است؛ هرگز اطلاعات حساس را از این طریق منتقل نکنید.

    آیا الان زمان مناسبی برای استفاده از RSC است؟

    RSC دیگر یک قابلیت آزمایشی نیست. در React 19 پایدار شده، به معماری پیش‌فرض پرکاربردترین فریم‌ورک‌های React تبدیل شده و اکوسیستم اطراف آن -از کتابخانه‌های مدیریت state گرفته تا ابزارهای دریافت داده و راهکارهای استایل‌دهی- تا حد زیادی خودش را با آن هماهنگ کرده است. سؤال اصلی این نیست که آیا RSC آماده‌ی محیط تولید است یا نه؛ سؤال این است که آیا استک فنی خاص شما (باندلر، فریم‌ورک، پلتفرم دیپلوی) از آن پشتیبانی کامل می‌کند یا نه، چون RSC نسبت به یک ویژگی معمولی React، به یکپارچگی عمیق‌تری با ابزارهای build نیاز دارد. اگر روی فریم‌ورکی کار می‌کنید که پشتیبانی از RSC را به‌صورت آماده ارائه می‌دهد، دلیل چندانی برای دوری از آن وجود ندارد؛ فقط کاهش حجم جاوااسکریپت سمت کلاینت معمولاً ارزش تغییر مدل ذهنی را دارد.

    هوش مصنوعی

    نویسنده:

    هوش مصنوعی
    دقیقه:8
    انتشار :۱۴۰۵/۵/۶
    آپدیت :۱۴۰۵/۵/۶

    دسته بندی ها

    فرانت‌اند

    تگ ها

    #React#React Server Components#RSC#React 19#Frontend Architecture