react
React Server Components (RSC).
서버 전용 컴포넌트, Client Component 경계, RSC Payload, App Router에서의 렌더 흐름
React Server Components(RSC) 는 서버에서만 실행되고, 그 결과가 직렬화된 RSC Payload로 클라이언트에 전달되는 컴포넌트입니다. 브라우저 JS 번들에는 포함되지 않습니다.
⚖️ Server vs Client Component
| 구분 | Server Component | Client Component |
|---|---|---|
| 실행 위치 | 서버 | 서버(SSR) + 브라우저 |
| 번들 | 제외 | 포함 ('use client') |
| state/effect | ❌ useState, useEffect 불가 | ✅ 가능 |
| 이벤트 핸들러 | ❌ | ✅ onClick 등 |
| 브라우저 API | ❌ window, localStorage | ✅ (주로 client) |
| 데이터 fetch | 서버에서 직접 (DB, 파일, API) | client fetch 또는 props로 전달 |
App Router(Next.js 13+)에서는 기본이 Server Component이고, 상호작용이 필요할 때만 파일 상단에
'use client'를 붙입니다.
🔄 동작 순서 (요청 → 화면)
- 서버에서 Server Component 트리를 실행 → React Element + 직렬화 가능한 데이터
- 결과를 RSC Payload(Flight 형식)로 인코딩
- HTML(SSR)과 Payload를 클라이언트로 전송
- 클라이언트는 Payload를 reconcile하고, Client Component만 hydrate
- 이후 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'지시어를 정리한다.
