핵심 요약
React Server Components(RSC)는 서버에서만 실행되는 컴포넌트다. 클라이언트 번들에 포함되지 않아 초기 페이지 크기를 획기적으로 줄이고, DB·파일 시스템·내부 API에 직접 접근할 수 있다.
- 서버에서 실행 → 번들 사이즈 감소, 보안 향상
- 비동기 컴포넌트 지원 →
async function Component() - Streaming SSR과 결합 → 사용자 체감 속도 향상
- 'use client' / 'use server' 디렉티브로 경계 제어
서버 컴포넌트와 클라이언트 컴포넌트의 경계
App Router에서 모든 컴포넌트는 기본이 서버 컴포넌트다. 이벤트 핸들러·useState·useEffect가 필요하면 파일 최상단에 'use client'를 선언한다.
// app/dashboard/page.tsx (서버 컴포넌트)
import { db } from '@/lib/db';
import { ClientChart } from './chart';
export default async function Dashboard() {
const stats = await db.stats.findMany();
return <ClientChart data={stats} />;
}
// app/dashboard/chart.tsx (클라이언트 컴포넌트)
'use client';
import { useState } from 'react';
export function ClientChart({ data }: { data: Stat[] }) {
const [range, setRange] = useState('7d');
// ...
}
규칙: 서버 → 클라이언트 props 전달은 직렬화 가능한 값만. 함수·Date 인스턴스·Class 인스턴스는 전달되지 않는다.
Server Actions ('use server')
폼 제출·뮤테이션을 서버에서 직접 처리한다. API 라우트를 만들 필요가 없다.
// app/todo/actions.ts
'use server';
export async function createTodo(formData: FormData) {
const title = formData.get('title') as string;
await db.todo.create({ data: { title } });
revalidatePath('/todo');
}
// app/todo/page.tsx
import { createTodo } from './actions';
export default function TodoPage() {
return (
<form action={createTodo}>
<input name="title" />
<button type="submit">추가</button>
</form>
);
}
Streaming과 Suspense
느린 데이터는 Suspense로 감싸서 부분 스트리밍한다. 빠른 영역은 먼저 보이고, 느린 영역은 나중에 채워진다.
<Suspense fallback={<Skeleton />}>
<SlowData />
</Suspense>
실무에서 자주 하는 실수
- 모든 컴포넌트에 'use client': RSC 이점 소멸. 상태가 필요한 리프만 클라이언트로.
- 서버 → 클라 함수 전달: 직렬화 불가로 런타임 에러. 데이터만 넘기고 로직은 Server Action으로.
- useEffect로 데이터 페칭 유지: RSC에서는 컴포넌트 본문에서
await로 직접 페칭.
자주 묻는 질문
RSC는 Next.js 전용인가?
표준 React 기능이지만, 현재 프레임워크 레벨에서 완전히 지원하는 건 Next.js App Router와 Remix 일부다.
SEO 영향은?
오히려 좋아진다. 서버에서 완전한 HTML을 생성하므로 크롤러가 콘텐츠를 즉시 수집할 수 있다.
레거시 프로젝트를 어떻게 점진 이관하나?
App Router 경로부터 도입하고, 기존 Pages Router와 공존 가능하다. 신규 페이지부터 RSC로 작성하는 전략이 안전하다.
댓글 0