React 19 서버 컴포넌트 딥다이브
React 19의 서버 컴포넌트가 프론트엔드 개발 패러다임을 어떻게 바꾸고 있는지 깊이 있게 살펴봅니다.
서버 컴포넌트란?
React 19에서 정식으로 도입된 서버 컴포넌트(Server Components)는 컴포넌트를 서버에서 렌더링하고, 그 결과만 클라이언트에 전달하는 새로운 패러다임입니다. 이를 통해 번들 사이즈를 획기적으로 줄이고, 데이터 페칭을 더 효율적으로 처리할 수 있습니다.
기존 방식의 한계
기존 클라이언트 사이드 렌더링(CSR)에서는 모든 컴포넌트 코드가 클라이언트로 전송되어야 했습니다. 데이터를 가져오기 위해 useEffect와 상태 관리 라이브러리를 조합해야 했고, 이는 불필요한 복잡성을 야기했습니다.
// ❌ 기존 방식: 클라이언트에서 데이터 페칭
"use client";
import { useState, useEffect } from "react";
export function PostList() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/posts")
.then((res) => res.json())
.then((data) => {
setPosts(data);
setLoading(false);
});
}, []);
if (loading) return <Spinner />;
return <ul>{posts.map((p) => <li key={p.id}>{p.title}</li>)}</ul>;
}
서버 컴포넌트의 해결책
서버 컴포넌트를 사용하면 컴포넌트 자체에서 직접 async/await로 데이터를 가져올 수 있습니다.
// ✅ 서버 컴포넌트: 서버에서 직접 데이터 페칭
import { db } from "@/lib/db";
export async function PostList() {
const posts = await db.post.findMany({
orderBy: { createdAt: "desc" },
});
return (
<ul>
{posts.map((p) => (
<li key={p.id}>{p.title}</li>
))}
</ul>
);
}
핵심 이점
1. 제로 번들 사이즈
서버 컴포넌트의 코드는 클라이언트 번들에 포함되지 않습니다. 무거운 라이브러리(예: marked, highlight.js)를 서버에서만 사용하면 클라이언트 번들 사이즈에 전혀 영향을 주지 않습니다.
2. 직접적인 백엔드 접근
데이터베이스, 파일 시스템, 내부 API에 직접 접근할 수 있어 별도의 API 레이어 없이도 데이터를 가져올 수 있습니다.
3. 자동 코드 스플리팅
"use client" 경계를 기준으로 자동으로 코드 스플리팅이 이루어집니다. 개발자가 수동으로 React.lazy()를 사용할 필요가 줄어듭니다.
실전 패턴
서버-클라이언트 경계 설계
서버 컴포넌트와 클라이언트 컴포넌트를 효과적으로 나누는 것이 핵심입니다:
Page (서버) → Layout (서버) → InteractiveWidget (클라이언트)
→ StaticContent (서버)
→ DataTable (서버) → SortButton (클라이언트)
원칙: 인터랙션이 필요한 가장 작은 단위만 클라이언트 컴포넌트로 만듭니다.
Streaming과 Suspense
서버 컴포넌트는 React Suspense와 결합하여 점진적 렌더링을 지원합니다:
import { Suspense } from "react";
export default function Dashboard() {
return (
<div>
<h1>대시보드</h1>
<Suspense fallback={<ChartSkeleton />}>
<AnalyticsChart />
</Suspense>
<Suspense fallback={<TableSkeleton />}>
<RecentOrders />
</Suspense>
</div>
);
}
마치며
서버 컴포넌트는 단순한 기능 추가가 아니라, 웹 애플리케이션을 설계하는 방식 자체를 변화시키는 패러다임 전환입니다. Next.js App Router와 함께 사용하면 그 진가를 충분히 발휘할 수 있습니다.
서버에서 할 수 있는 일은 서버에서 하고, 클라이언트에서만 할 수 있는 일(인터랙션, 브라우저 API)만 클라이언트에 맡기세요. 이 원칙을 지키면 자연스럽게 더 빠르고, 더 가벼운 애플리케이션을 만들 수 있습니다.