Client Components چیست

در درس قبل، Server Component را دیدیم: کامپوننتی که فقط روی سرور یا در زمان Build اجرا می‌شود و تعاملی نیست. اما یک برنامه واقعی تعامل دارد: دکمه‌ها، فرم‌ها، منوها. این بخش‌ها، Client Component هستند و این درس به آن‌ها می‌پردازد.

Client Component همان چیزی است که تا اینجا می‌نوشتیم

نکته‌ای که شاید غافلگیرکننده باشد: تقریباً هر کامپوننتی که در فصل‌های قبل این دوره نوشتیم (با useState، useEffect، Event Handler، Ref و Context)، یک Client Component بود. Client Component همان کامپوننت معمولی React است که می‌تواند همه آنچه را Server Component نمی‌توانست انجام دهد:

  • استفاده از Hookهای State و Effect
  • اتصال Event Handler مثل onClick و onChange
  • دسترسی به APIهای مرورگر مثل window، localStorage و navigator

دستور "use client"

در پروژه‌ای که از Server Components پشتیبانی می‌کند، کامپوننت‌ها به‌طور پیش‌فرض Server Component هستند. برای اینکه یک فایل Client Component شود، باید در بالاترین خط آن، پیش از هر import، این دستور را بنویسید:

jsx
// LikeButton.js
"use client";

import { useState } from "react";

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

  return (
    <button onClick={() => setLiked(!liked)}>
      {liked ? "پسندیده شد" : "پسندیدن"}
    </button>
  );
}

این دستور روی یک فایل (ماژول) اثر می‌گذارد، نه روی یک تابع تکی. معنایش این است: «از این فایل به بعد، همه چیز در بسته جاوااسکریپت مرورگر قرار می‌گیرد».

استفاده از Client Component داخل Server Component

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

jsx
// ProductPage.js (Server Component، بدون directive)
import LikeButton from "./LikeButton";

export default async function ProductPage({ id }) {
  const product = await db.products.find(id);

  return (
    <>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <LikeButton />
    </>
  );
}

در این مثال، عنوان و توضیح از پایگاه داده روی سرور خوانده می‌شوند و کدشان به مرورگر نمی‌رسد. فقط کد LikeButton برای مرورگر فرستاده می‌شود.

قاعده عملی: «use client» را تا پایین‌ترین حد ممکن ببرید

چون هر چیزی که از یک فایل "use client" import شود هم بخشی از بسته مرورگر می‌شود، اگر دستور را بالای یک کامپوننت بزرگ بگذارید، کل زیرمجموعه‌اش به مرورگر می‌رود. مشابه اصل State Colocation فصل سوم (State را نزدیک محل استفاده نگه دارید)، اینجا هم بهتر است Client Component را کوچک و نزدیک به همان بخش تعاملی نگه داریم و بقیه درخت را Server Component بگذاریم. مثلاً به‌جای Client کردن کل صفحه محصول، فقط دکمه پسندیدن را جدا کنید.

Client Component هم روی سرور پیش‌رندر می‌شود

اسم «Client» ممکن است گمراه‌کننده باشد. در Frameworkهای رایج، Client Componentها هم برای نمایش سریع اولیه، روی سرور به HTML تبدیل (SSR) می‌شوند، و بعد در مرورگر Hydrate می‌شوند تا تعاملی شوند. تفاوت اصلی با Server Component این است که کد Client Component به مرورگر فرستاده می‌شود و آنجا دوباره اجرا می‌شود؛ نه این‌که اصلاً روی سرور اجرا نشود.

چند نکته که در درس‌های بعد کامل می‌شوند

  • اینکه دقیقاً کجا مرز Server/Client قرار می‌گیرد و چه چیزی را می‌توان از طریق آن رد و بدل کرد (درس ۲۴-۳).
  • محدودیت داده‌هایی که می‌توان از Server Component به Client Component فرستاد (درس ۲۴-۴).

چرا این درس مثال قابل اجرا ندارد

دستور "use client" فقط وقتی معنا دارد که یک Bundler یا Framework با پشتیبانی از Server Components، فایل‌ها را به دو محیط جدا تقسیم کند. این ویژگی در ویرایشگر درون‌صفحه‌ای وجود ندارد؛ کدهای این درس را در یک پروژه با Framework مناسب اجرا کنید.

جمع‌بندی

Client Component همان کامپوننت معمولی React است که می‌تواند State، Effect، Event Handler و APIهای مرورگر داشته باشد. با نوشتن "use client" در بالای یک فایل، آن فایل و هر چیزی که import می‌کند، به بسته مرورگر می‌رود. Server Component می‌تواند Client Component را رندر کند، و بهترین کار این است که "use client" را روی کوچک‌ترین بخش تعاملی بگذاریم. Client Componentها روی سرور هم پیش‌رندر می‌شوند، اما کدشان به مرورگر می‌رسد. در درس بعدی، به مرز Server/Client می‌پردازیم.