React Server Components (RSC)는 React 애플리케이션을 구축하는 방식을 근본적으로 변화시켰습니다. 렌더링 로직을 서버로 이동함으로써 클라이언트에 전송되는 JavaScript 번들을 크게 줄일 수 있으며, 이는 더 빠른 로드 시간과 더 나은 사용자 경험으로 이어집니다. 이 글에서는 2026년에 RSC를 활용하기 위한 고급 패턴과 모범 사례를 살펴보겠습니다.
Server Components란 무엇인가?
전통적으로 React 컴포넌트는 클라이언트에서 완전히 렌더링(CSR)되거나 서버에서 HTML로 사전 렌더링(SSR)된 후 클라이언트에서 hydration되었습니다. Server Components는 컴포넌트를 서버에서만 렌더링할 수 있게 해줍니다. 이 코드는 절대 브라우저로 전송되지 않습니다.
이점
- 제로 번들 사이즈: Server Components에서 사용되는 의존성(마크다운 파서나 무거운 날짜 라이브러리 등)은 서버에 남습니다.
- 직접적인 백엔드 접근: API 엔드포인트를 노출하지 않고도 컴포넌트 내에서 직접 데이터베이스를 쿼리할 수 있습니다.
- 자동 코드 분할: 서버 사이드에서 임포트된 Client components는 자동으로 코드 분할됩니다.
데이터 페칭 패턴
RSC를 사용하면 컴포넌트를 async로 만들고 데이터를 직접 await할 수 있습니다.
// app/users/page.tsx import { db } from '@/lib/db'; export default async function UsersPage() { const users = await db.user.findMany(); return ( <main> <h1>Users</h1> <ul> {users.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> </main> ); }
스트리밍을 위한 Suspense
데이터 페칭이 느릴 수 있으므로, 데이터가 로드되는 동안 즉시 폴백 UI를 표시하기 위해 컴포넌트를 <Suspense>로 감싸세요.
import { Suspense } from 'react'; import UserList from './UserList'; import LoadingSkeleton from './LoadingSkeleton'; export default function Page() { return ( <section> <h1>My Users</h1> <Suspense fallback={<LoadingSkeleton />}> <UserList /> </Suspense> </section> ); }
Server와 Client Components 혼합하기
가장 혼란스러운 부분 중 하나는 Server와 Client components를 어떻게 조합하는가입니다.
기본 규칙: Server Components는 Client Components를 임포트할 수 있습니다. Client Components는 Server Components를 직접 임포트할 수 없습니다. 하지만 Server Component를 Client Component에 children으로 전달할 수 있습니다.
"Children" 패턴
// ClientComponent.tsx 'use client'; import { useState } from 'react'; export default function ClientWrapper({ children }) { const [count, setCount] = useState(0); return ( <div onClick={() => setCount((c) => c + 1)}> Count: {count} {children} {/* This can be a Server Component! */} </div> ); }
// ServerPage.tsx import ClientWrapper from './ClientWrapper'; import ServerContent from './ServerContent'; export default function Page() { return ( <ClientWrapper> <ServerContent /> {/* This works perfectly */} </ClientWrapper> ); }
일반적인 함정
- Server Components에서 Context 사용: Context는 클라이언트 사이드 개념입니다. 서버 사이드에서 데이터를 공유해야 한다면 props로 전달하거나 전문적인 요청 범위 캐시를 사용하세요.
- 이벤트 핸들러 추가: Server Component에
onClick이나onChange를 추가할 수 없습니다. 해당 로직은 일반 Client Component 리프 노드에 속합니다.
결론
React Server Components는 단순한 기능이 아닙니다. 패러다임의 전환입니다. 서버와 클라이언트의 경계를 이해함으로써, 높은 상호작용성과 놀라운 속도를 동시에 갖춘 애플리케이션을 구축할 수 있습니다.