Contents
see List개요
React Server Components(RSC)는 React 애플리케이션의 아키텍처를 근본적으로 변화시키는 기술입니다. 컴포넌트를 서버에서 실행하고 그 결과만 클라이언트로 전송함으로써, 번들 크기 감소와 초기 로딩 성능 향상을 동시에 달성합니다. React 19와 Next.js 15에서 안정화된 RSC의 동작 원리와 실전 패턴을 깊이 있게 살펴봅니다.
핵심 개념
서버 컴포넌트와 클라이언트 컴포넌트의 구분: React Server Components는 기본적으로 모든 컴포넌트가 서버 컴포넌트입니다. 클라이언트에서 실행이 필요한 컴포넌트만 파일 상단에 'use client' 지시어를 추가합니다.
RSC Payload: 서버 컴포넌트의 렌더링 결과는 RSC Payload라는 특수한 직렬화 포맷으로 클라이언트에 전달됩니다. 이 포맷은 HTML보다 가볍고, React가 클라이언트 컴포넌트와 합성하기에 최적화되어 있습니다.
번들 경계: 'use client'는 서버와 클라이언트의 경계를 정의합니다. 이 경계를 넘어가는 props는 직렬화 가능해야 하므로, 함수나 클래스 인스턴스는 전달할 수 없습니다.
스트리밍: 서버 컴포넌트는 Suspense와 결합하여 점진적으로 렌더링됩니다. 느린 데이터 페칭이 있는 부분은 나중에 스트리밍되어 전체 페이지 로딩을 차단하지 않습니다.
실전 예제
서버 컴포넌트에서 직접 데이터를 조회하고, 클라이언트 컴포넌트와 조합하는 패턴입니다.
// app/dashboard/page.tsx (서버 컴포넌트)
import { Suspense } from 'react';
import { UserStats } from './UserStats';
import { RecentActivity } from './RecentActivity';
import { InteractiveChart } from './InteractiveChart';
export default async function DashboardPage() {
// 서버에서 직접 DB 조회 - 클라이언트에 노출 안됨
const user = await db.user.findUnique({
where: { id: getCurrentUserId() }
});
return (
<div className="dashboard">
<h1>{user.name}님의 대시보드</h1>
<Suspense fallback={<StatsSkeleton />}>
<UserStats userId={user.id} />
</Suspense>
<Suspense fallback={<ActivitySkeleton />}>
<RecentActivity userId={user.id} />
</Suspense>
{/* 클라이언트 컴포넌트 - 인터랙션 필요 */}
<InteractiveChart userId={user.id} />
</div>
);
}
클라이언트 컴포넌트를 올바르게 분리하는 패턴입니다.
// components/InteractiveChart.tsx
'use client';
import { useState, useEffect } from 'react';
interface ChartProps {
userId: number; // 직렬화 가능한 props만 받을 수 있음
}
export function InteractiveChart({ userId }: ChartProps) {
const [period, setPeriod] = useState('week');
const [data, setData] = useState(null);
useEffect(() => {
fetch(`/api/chart-data?userId=${userId}&period=${period}`)
.then(res => res.json())
.then(setData);
}, [userId, period]);
return (
<div>
<select value={period} onChange={e => setPeriod(e.target.value)}>
<option value="week">주간</option>
<option value="month">월간</option>
</select>
{data && <Chart data={data} />}
</div>
);
}
활용 팁
- 컴포넌트 경계를 최대한 아래로 내리세요. 'use client'를 페이지 레벨이 아닌 실제 인터랙션이 필요한 최소 단위에 배치하면 번들 크기가 줄어듭니다.
- 서버 컴포넌트에서 민감한 로직을 실행하세요. API 키, DB 접근 등은 서버 컴포넌트에서 처리하면 클라이언트에 노출되지 않습니다.
- Composition 패턴을 활용하세요. 서버 컴포넌트가 클라이언트 컴포넌트를 children으로 감싸면, 서버에서 가져온 데이터를 클라이언트 컴포넌트의 컨텍스트로 전달할 수 있습니다.
- 서드파티 라이브러리 호환성을 확인하세요. useState, useEffect를 사용하는 라이브러리는 클라이언트 컴포넌트에서만 사용할 수 있습니다.
- 서버 컴포넌트 간 데이터 공유에는 React.cache()를 사용하여 중복 요청을 방지하세요.
마무리
React Server Components는 단순한 기능 추가가 아닌 React의 멘탈 모델 자체를 확장하는 혁신입니다. 서버와 클라이언트의 역할을 명확히 분리하고, 각 환경의 장점을 최대한 활용하는 것이 핵심입니다. 초기 학습 곡선이 있지만, 적응하면 성능과 개발자 경험 모두에서 큰 이점을 얻을 수 있습니다.