React Server Components در Next.js؛ نگاهی عمیق به آینده‌ی رندر وب

React Server Components در Next.js؛ نگاهی عمیق به آینده‌ی رندر وب

توسعه‌دهنده فرانت‌اند

با معرفی App Router در Next.js، مفهوم React Server Components (RSC) به یکی از مهم‌ترین تغییرات سال‌های اخیر در دنیای فرانت‌اند تبدیل شد. در این بلاگ بررسی می‌کنیم RSC چیست، چه تفاوتی با SSR سنتی دارد و چطور می‌توانیم از آن برای ساخت اپلیکیشن‌هایی سریع‌تر و سبک‌تر استفاده کنیم.

React Server Components در Next.js؛ نگاهی عمیق به آینده‌ی رندر وب

فاطمه زارعی

۴ دقیقه مطالعه

۲ نفر

۱۴۰۵/۶/۳۰

React Server Components یا به‌اختصار RSC، یکی از بزرگ‌ترین پارادایم شیفت‌هایی است که بعد از معرفی هوک‌ها در React شاهدش بوده‌ایم. برای سال‌ها، ما به این عادت داشتیم که تمام کامپوننت‌هایمان در مرورگر اجرا شوند؛ حتی آن‌هایی که هیچ تعاملی با کاربر نداشتند. نتیجه‌ی این رویکرد، باندل‌های حجیم جاوااسکریپت، زمان بارگذاری طولانی و مصرف زیاد منابع کاربر بود.

با آمدن App Router در Next.js 13 و تکمیل آن در نسخه‌های بعدی، مفهوم Server Component رسماً به جریان اصلی توسعه‌ی وب وارد شد. ایده‌ی اصلی ساده است: کامپوننتی که به state، event handler یا lifecycle نیاز ندارد، می‌تواند کاملاً روی سرور اجرا شود و فقط خروجی HTML آن برای مرورگر ارسال گردد. این یعنی صفر بایت جاوااسکریپت برای آن کامپوننت در سمت کلاینت.

نکته‌ی مهمی که باید درک کنیم این است که RSC با SSR سنتی متفاوت است. در SSR کلاسیک، کامپوننت‌ها یک بار روی سرور رندر می‌شدند و بعد دوباره روی کلاینت hydration می‌شدند؛ یعنی کد جاوااسکریپت آن‌ها باید همه‌جا ارسال می‌شد. اما در RSC، hydration اصلاً اتفاق نمی‌افتد. کامپوننت روی سرور اجرا می‌شود، به دیتابیس یا API دسترسی دارد و خروجی نهایی به‌صورت یک درخت سریالایز‌شده به کلاینت می‌رسد.

برای درک بهتر این تفاوت، یک مثال ساده کمک‌کننده است. فرض کنید یک صفحه‌ی جزئیات محصول دارید. در SSR سنتی، سرور HTML اولیه را می‌سازد، اما مرورگر هنوز باید کل کد جاوااسکریپت کامپوننت را دانلود و اجرا کند تا صفحه interactive شود. در RSC، کامپوننت محصول روی سرور اجرا می‌شود، داده را از دیتابیس می‌گیرد و خروجی نهایی را به شکل یک ساختار سبک به کلاینت می‌فرستد. یعنی مرورگر فقط HTML و بخش کوچکی از کد را برای تعاملات ضروری دریافت می‌کند. همین مسئله باعث می‌شود زمان بارگذاری اولیه و حجم باندل به‌طور محسوس کاهش پیدا کند.

در App Router، به‌صورت پیش‌فرض همه‌ی کامپوننت‌ها Server Component هستند. برای ساختن یک Client Component باید حتماً در ابتدای فایل عبارت "use client" را بنویسیم. این رویکرد باعث می‌شود توسعه‌دهنده به‌صورت آگاهانه تصمیم بگیرد کدام بخش از UI واقعاً نیاز به تعامل دارد. مثلاً یک صفحه‌ی محصول می‌تواند کاملاً Server Component باشد، ولی دکمه‌ی «افزودن به سبد خرید» به‌عنوان یک Client Component جداگانه تعریف شود.

یکی از مزیت‌های بزرگ RSC، امکان fetch مستقیم داده روی سرور است. دیگر نیازی به استفاده از useEffect برای واکشی اولیه‌ی داده نداریم. می‌توانیم داخل خود کامپوننت، تابع async صدا بزنیم و نتیجه را مستقیم رندر کنیم. این مسئله کد را بسیار ساده‌تر می‌کند و از waterfall معروف «fetch کردن سپس رندر کردن» جلوگیری می‌کند.

از نظر امنیتی هم RSC مزایایی دارد. چون کد کامپوننت روی سرور می‌ماند، می‌توانیم بدون نگرانی از لو رفتن API Key یا توکن‌های حساس، مستقیماً به سرویس‌های داخلی وصل شویم. دیگر لازم نیست یک لایه‌ی API میانی بسازیم فقط برای اینکه کلیدها را مخفی نگه داریم.

اما چالش‌ها هم وجود دارد. مهم‌ترین چالش، تغییر ذهنیت توسعه‌دهنده است. سال‌ها عادت کرده‌ایم همه‌چیز را در سمت کلاینت بنویسیم و حالا باید بیاموزیم کدام منطق در کدام سمت اجرا شود. همچنین مسائلی مثل مدیریت state بین سرور و کلاینت، الگوهای کش و تعامل با کتابخانه‌های ثالث که فرض می‌کنند در مرورگر اجرا می‌شوند، می‌توانند دردسرساز باشند.

در عمل، مهاجرت به RSC یک شبه اتفاق نمی‌افتد و بهتر است تیم‌ها آن را به‌صورت تدریجی انجام دهند. می‌توانید از صفحات کم‌تعامل مثل وبلاگ، مستندات یا صفحه‌های محصول شروع کنید و بعد کم‌کم بخش‌های پیچیده‌تر را جلو ببرید. استفاده از الگوی Composition، یعنی پاس دادن Server Componentها به‌عنوان children به Client Componentها، یکی از بهترین راه‌ها برای ترکیب این دو دنیاست. همچنین اندازه‌گیری مداوم با ابزارهایی مثل React DevTools و Lighthouse کمک می‌کند بفهمید کدام بخش‌ها واقعاً سود بیشتری از انتقال به سرور می‌برند.

جمع‌بندی اینکه، RSC یک ابزار انقلابی نیست که همه‌ی مشکلات را حل کند، اما بدون شک جهت‌گیری آینده‌ی React است. اگر امروز پروژه‌ای با Next.js App Router شروع می‌کنید، یادگیری درست این مفهوم می‌تواند تفاوت بین یک اپلیکیشن کند و یک اپلیکیشن فوق‌سریع باشد. توصیه می‌کنم از پروژه‌های کوچک شروع کنی، بخش‌های بدون تعامل UI را به Server Component تبدیل کنی و به‌تدریج این الگو را در کل پروژه پیاده کنی.