mason
mason-log.

mason

mason.

안녕하세요. mason 입니다.

react

React Server Components (RSC).

서버 전용 컴포넌트, Client Component 경계, RSC Payload, App Router에서의 렌더 흐름

React Server Components(RSC)서버에서만 실행되고, 그 결과가 직렬화된 RSC Payload로 클라이언트에 전달되는 컴포넌트입니다. 브라우저 JS 번들에는 포함되지 않습니다.

⚖️ Server vs Client Component

구분Server ComponentClient Component
실행 위치서버서버(SSR) + 브라우저
번들제외포함 ('use client')
state/effectuseState, useEffect 불가✅ 가능
이벤트 핸들러onClick
브라우저 APIwindow, localStorage✅ (주로 client)
데이터 fetch서버에서 직접 (DB, 파일, API)client fetch 또는 props로 전달

App Router(Next.js 13+)에서는 기본이 Server Component이고, 상호작용이 필요할 때만 파일 상단에 'use client'를 붙입니다.

🔄 동작 순서 (요청 → 화면)

RSC 서버 클라이언트 경계와 Flight

  1. 서버에서 Server Component 트리를 실행 → React Element + 직렬화 가능한 데이터
  2. 결과를 RSC Payload(Flight 형식)로 인코딩
  3. HTML(SSR)과 Payload를 클라이언트로 전송
  4. 클라이언트는 Payload를 reconcile하고, Client Component만 hydrate
  5. 이후 navigation 시에도 필요한 chunk 단위로 Payload를 추가 요청 (partial rendering)
[Server]  Page (RSC) → DB fetch → RSC Payload
                ↓
[Client]  HTML paint → Client Component hydrate → 인터랙션

📦 RSC Payload와 직렬화

  • Server Component의 return 값(JSX 트리)은 JSON처럼 직렬화되어 전달됩니다.
  • props로 넘길 수 있는 것: plain object, string, number, array, Date, Map/Set(제한적), Promise(Suspense와 함께) 등
  • 넘길 수 없는 것: 함수, class instance, Symbol, DOM ref, 대부분의 클래스 컴포넌트 패턴
  • Client Component에 Server Component를 props로 직접 넣을 수 있음 (children, header={<ServerHeader />})
// app/page.tsx — Server Component (기본)
import { ClientCounter } from './ClientCounter';

export default async function Page() {
  const posts = await db.posts.findMany();
  return (
    <main>
      <h1>Posts</h1>
      <ClientCounter initial={posts.length} />
    </main>
  );
}
// ClientCounter.tsx
'use client';

import { useState } from 'react';

export function ClientCounter({ initial }: { initial: number }) {
  const [count, setCount] = useState(initial);
  return <button onClick={() => setCount((c) => c + 1)}>{count}</button>;
}
  • Server Component: 데이터 조회, 레이아웃, 정적 UI, 무거운 의존성(마크다운 파서, ORM) — 번들 크기 절감
  • Client Component: 입력, 애니메이션, 브라우저 API, Recoil/Zustand 등 client state
  • 'use client'파일 단위 — 해당 파일 import는 전부 client 번들로 감
  • leaf에 가깝게 'use client'를 두는 편이 번들을 작게 유지
  • Pages Router(이 블로그)는 RSC 미지원 — App Router 전용 개념. SSR(getServerSideProps)과는 다른 축

🔗 참고 자료

  • Server Components — RSC의 역할과 제약을 설명한다.
  • 'use client' — Client Component 경계를 선언하는 지시어다.
  • Directives'use client', 'use server' 지시어를 정리한다.