راهنمای کاربردی React Server Components

تفاوت کامپوننت سرور و کلاینت، دریافت داده بدون API، ترکیب درست use client، Streaming با Suspense و اشتباهات رایج در Next.js App Router.

راهنمای کاربردی React Server Components
زمان انتشار:
۲۷ مرداد ۱۴۰۵
زمان مطالعه:
حدود 3 دقیقه
نویسنده:
علیرضا مهدی زاده

React Server Components؛ تغییر بزرگ در معماری React

سال‌ها روش معمول ساخت اپلیکیشن React این بود: مرورگر یک صفحه‌ی خالی دریافت می‌کند، جاوااسکریپت را دانلود می‌کند، سپس داده را از API می‌گیرد و در نهایت محتوا نمایش داده می‌شود. React Server Components (RSC) این جریان را از اساس تغییر داده‌اند. حالا بخشی از کامپوننت‌ها فقط روی سرور اجرا می‌شوند، مستقیماً به پایگاه داده دسترسی دارند و هیچ کدی از آن‌ها به مرورگر ارسال نمی‌شود.

لپ‌تاپ روشن کنار دفترچه‌ی یادداشت و هدفون روی میز چوبی؛ شروع یادگیری معماری جدید React

کامپوننت سرور در مقابل کامپوننت کلاینت

در Next.js با App Router، همه‌ی کامپوننت‌ها به‌صورت پیش‌فرض کامپوننت سرور هستند. هر جا به تعامل با کاربر نیاز داشتید، با افزودن دستور "use client" یک کامپوننت کلاینت می‌سازید.

ویژگی کامپوننت سرور کامپوننت کلاینت
دسترسی مستقیم به پایگاه داده بله خیر
استفاده از useState و useEffect خیر بله
رویدادهایی مثل onClick خیر بله
افزودن حجم به باندل جاوااسکریپت خیر بله

دریافت داده بدون API

قدرت اصلی RSC این است که کامپوننت می‌تواند async باشد و داده را همان‌جا دریافت کند:

import { prisma } from "@/lib/prisma"

export default async function LatestPosts() {
  const posts = await prisma.post.findMany({
    where: { published: true },
    orderBy: { publishedAt: "desc" },
    take: 5,
  })

  return (
    <ul className="space-y-3">
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

نه useEffect، نه وضعیت لودینگ و نه یک Endpoint اضافه. کتابخانه‌ی Prisma و کوئری‌ها هرگز به مرورگر نمی‌رسند.

لپ‌تاپ و دست‌های توسعه‌دهنده در حال تایپ؛ نوشتن کامپوننت‌های async روی سرور

ترکیب سرور و کلاینت

بهترین الگو این است که «جزیره‌های تعاملی» را تا حد ممکن کوچک نگه دارید. کامپوننت سرور داده را آماده می‌کند و فقط بخش تعاملی را به کامپوننت کلاینت می‌سپارد:

// LikeButton.tsx
"use client"
import { useState } from "react"

export function LikeButton({ initial }: { initial: number }) {
  const [likes, setLikes] = useState(initial)
  return <button onClick={() => setLikes(likes + 1)}>❤ {likes}</button>
}
// PostPage.tsx (کامپوننت سرور)
import { LikeButton } from "./LikeButton"

export default async function PostPage({ id }: { id: number }) {
  const post = await getPost(id)
  return (
    <article>
      <h1>{post.title}</h1>
      <LikeButton initial={post.likes} />
    </article>
  )
}

دقت کنید که فقط داده‌های قابل سریال‌سازی (مثل عدد، رشته و آبجکت ساده) را می‌توان از سرور به کلاینت پاس داد؛ تابع یا نمونه‌ی کلاس قابل انتقال نیست.

نمای پایین به بالای آسمان‌خراش شیشه‌ای؛ لایه‌های سرور و کلاینت در یک ساختار یکپارچه

Streaming و Suspense

وقتی بخشی از صفحه به داده‌ای کند وابسته است، لازم نیست کل صفحه منتظر بماند. با Suspense بخش سریع فوراً ارسال می‌شود و بخش کند به‌محض آماده شدن، به‌صورت جریانی (Streaming) جایگزین اسکلت لودینگ می‌شود:

<Suspense fallback={<CommentsSkeleton />}>
  <Comments postId={post.id} />
</Suspense>

اشتباهات رایج

  • استفاده‌ی بی‌مورد از use client: قرار دادن این دستور بالای صفحه‌ی اصلی، تمام مزایای RSC را از بین می‌برد.
  • ارسال اطلاعات حساس به کلاینت: آبجکت کامل کاربر را پاس ندهید؛ فقط فیلدهای موردنیاز را انتخاب کنید.
  • فراموش کردن کش: برای داده‌هایی که کم تغییر می‌کنند، از قابلیت‌های کش Next.js استفاده کنید.
  • کوئری‌های تکراری: با تابع cache از React، یک کوئری را در یک درخواست چند بار اجرا نکنید.

ساختمان‌های قدیمی و بلند شهری در نمای سیاه‌وسفید؛ معماری مستحکم برای اپلیکیشن‌های بزرگ

جمع‌بندی

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

دیدگاه‌ها

برای ثبت دیدگاه باید شماره موبایل خود را تأیید کنید.

هنوز دیدگاهی ثبت نشده است. اولین نفر باشید!