کامپوننت‌های سمت سرور و کلاینت در Next.js – رندر، انتقال داده، و بهینه‌سازی باندل جاوااسکریپت

Next.js از ترکیب کامپوننت‌های سروری و کلاینتی برای ساخت رابط‌های سریع و تعاملی استفاده می‌کند. در این مقاله، با مفهوم RSC Payload، نحوهٔ رندر سمت سرور، انتقال داده بین کامپوننت‌ها، استفاده از دستور "use client"، مدیریت context، و جلوگیری از افشای متغیرهای محیطی آشنا می‌شویم.

Server ComponentClient ComponentRSC Payloaduse client

~3 دقیقه مطالعه • بروزرسانی ۳ آبان ۱۴۰۴

رندر سمت سرور در Next.js


Next.js از APIهای React برای رندر سمت سرور استفاده می‌کند. کامپوننت‌های سروری به فرمت خاصی به نام React Server Component Payload (RSC) تبدیل می‌شوند. این payload شامل:


  • نتیجهٔ رندر کامپوننت‌های سروری
  • جایگاه کامپوننت‌های کلاینتی و مسیر فایل‌های جاوااسکریپت آن‌ها
  • پراپ‌هایی که از سرور به کلاینت ارسال می‌شوند

رندر سمت کلاینت و فرآیند Hydration


در بارگذاری اولیه:

  • HTML برای نمایش سریع و غیرتعاملی استفاده می‌شود
  • RSC Payload برای تطبیق درخت کامپوننت‌ها استفاده می‌شود
  • جاوااسکریپت برای فعال‌سازی تعاملات (hydration) استفاده می‌شود

Hydration فرآیندی است که React با آن event handlerها را به DOM متصل می‌کند.


استفاده از کامپوننت‌های کلاینتی


برای تعریف کامپوننت کلاینتی، از دستور 'use client' در ابتدای فایل استفاده می‌شود:


// app/ui/counter.tsx
'use client'
import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)
  return (
    <div>
      <p>{count} likes</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}

نیازی نیست این دستور را در تمام کامپوننت‌های فرزند تکرار کنید؛ کافی است در ریشهٔ کلاینتی باشد.


کاهش حجم باندل جاوااسکریپت


به‌جای تبدیل کل layout به کامپوننت کلاینتی، فقط بخش‌های تعاملی مانند <Search /> را کلاینتی کنید:


// app/layout.tsx
import Search from './search'
import Logo from './logo'

export default function Layout({ children }) {
  return (
    <nav>
      <Logo />
      <Search />
    </nav>
    <main>{children}</main>
  )
}

ارسال داده از سرور به کلاینت


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


// app/[id]/page.tsx
import LikeButton from '@/app/ui/like-button'
import { getPost } from '@/lib/data'

export default async function Page({ params }) {
  const { id } = await params
  const post = await getPost(id)
  return <LikeButton likes={post.likes} />
}

ترکیب کامپوننت‌های سروری و کلاینتی


می‌توان کامپوننت سروری را به‌عنوان فرزند به کامپوننت کلاینتی ارسال کرد. مثلاً:


// app/ui/modal.tsx
'use client'
export default function Modal({ children }) {
  return <div>{children}</div>
}

// app/page.tsx
import Modal from './ui/modal'
import Cart from './ui/cart'

export default function Page() {
  return (
    <Modal>
      <Cart />
    </Modal>
  )
}

استفاده از Context در کامپوننت‌های کلاینتی


React context در کامپوننت‌های سروری پشتیبانی نمی‌شود. برای استفاده از context، باید آن را در کامپوننت کلاینتی تعریف کنید:


// app/theme-provider.tsx
'use client'
import { createContext } from 'react'
export const ThemeContext = createContext({})
export default function ThemeProvider({ children }) {
  return <ThemeContext.Provider value="dark">{children}</ThemeContext.Provider>
}

استفاده از کامپوننت‌های شخص ثالث


کامپوننت‌هایی مانند <Carousel /> که از ویژگی‌های کلاینتی استفاده می‌کنند، باید در کامپوننت کلاینتی قرار گیرند:


// app/gallery.tsx
'use client'
import { Carousel } from 'acme-carousel'

export default function Gallery() {
  return <Carousel />
}

جلوگیری از افشای متغیرهای محیطی


فقط متغیرهایی که با NEXT_PUBLIC_ شروع می‌شوند در کلاینت قابل دسترسی هستند. برای جلوگیری از استفادهٔ ناخواسته، از پکیج server-only استفاده کنید:


// lib/data.ts
import 'server-only'

export async function getData() {
  const res = await fetch('https://...', {
    headers: { authorization: process.env.API_KEY }
  })
  return res.json()
}

جمع‌بندی


Next.js با ترکیب کامپوننت‌های سروری و کلاینتی، امکان ساخت رابط‌های سریع، امن و تعاملی را فراهم می‌کند. با استفاده از دستور 'use client'، مدیریت context، و کنترل دقیق باندل‌ها، می‌توان اپلیکیشن‌هایی مقیاس‌پذیر و بهینه ساخت.


نوشته و پژوهش شده توسط دکتر شاهین صیامی