RSC — 서버 컴포넌트와 클라이언트 컴포넌트 이해하기
React
들어가며
Next.js 13 이후로 React는 서버 컴포넌트(Server Component) 개념을 본격적으로 도입했다.
처음 문서만 읽었을 때는 기존 CSR, SSR과 뭐가 다르지?하고 이해를 못했었는데, 실제로 프로젝트에 적용해보며 렌더링 방식 자체가 바뀌는 변화라는 점을 배울 수 있었다.
이번 글에서는 서버 컴포넌트와 클라이언트 컴포넌트가 무엇인지, 왜 등장했는지, 언제 어떻게 사용해야 하는지 정리해보려 한다.
왜 서버 컴포넌트인가
기존 렌더링 방식이 가진 한계는 다음과 같다.
| 방식 | 설명 | 한계 |
|---|---|---|
| CSR | 모든 렌더링을 클라이언트에서 | 초기 로딩이 느리고 JS 의존도 큼 |
| SSR | 서버에서 HTML을 생성 | 클라이언트에서 다시 하이드레이션 필요 |
| SSG | 빌드 시 HTML 생성 | 데이터가 자주 바뀌면 적합하지 않음 |
만약 여기서 불필요한 자바스크립트를 클라이언트에 보내지 않으려면?
이 고민에서 나온 방안이 서버 컴포넌트다. 즉, UI 계산을 서버에서 수행하고 브라우저에는 최소한의 결과만 전달하는 방식이다.
서버 컴포넌트와 클라이언트 컴포넌트
서버 컴포넌트
- 서버에서 실행됨
- DB 쿼리, 파일 접근, 서버 API 호출 가능
- 브라우저에 JS가 내려가지 않음
- onClick 같은 브라우저 이벤트는 사용할 수 없음
// app/dashboard/page.tsx
import { getUser } from "@/lib/db";
export default async function Dashboard() {
const user = await getUser();
return <h1>Welcome, {user.name}</h1>;
}
클라이언트 컴포넌트
- 브라우저에서 실행됨
- 이벤트 핸들링 및 상태 관리 가능
- JS 번들에 포함됨
"use client";
export default function Button() {
const handleClick = () => alert("clicked");
return <button onClick={handleClick}>Click me</button>;
}
요약
| 구분 | Server Component | Client Component |
|---|---|---|
| 실행 위치 | 서버 | 브라우저 |
| 상태/Hook | X | 가능 |
| 이벤트 | X | 가능 |
| DB 접근 | 가능 | 불가 |
| 번들 포함 | X | 포함 |
RSC 사용 시 흔한 실수
use client 남발하는 경우
습관처럼 파일 상단에 붙이면 모든 컴포넌트가 클라이언트가 되고, 서버 컴포넌트의 장점이 사라진다. 실제로 상태가 필요한 컴포넌트에만 붙이는 것이 좋다.
서버 컴포넌트에서 함수 props 전달하는 경우
서버에서 실행되는 함수는 브라우저로 전달될 수 없다.
// 잘못된 예
function Parent() {
const onClick = () => {};
return <Child onClick={onClick} />;
}
대신 하위에 클라이언트 컴포넌트를 둔다.
import ClientButton from "./ClientButton";
export default function Parent() {
return <ClientButton />;
}
실제 프로젝트에서 느낀 장점
RSC를 실제로 사용하며 느낀 점은 다음과 같다.
| 항목 | 체감 |
|---|---|
| 번들 크기 감소 | 30 ~ 40% 감소 경험 |
| 초기 로딩 속도 개선 | 확실히 체감됨 |
| 서버 API 레이어 단순화 | UI 컴포넌트에서 직접 DB 접근 가능 |
| 보안 측면 | 민감 로직이 클라이언트로 내려가지 않음 |
특히 서버 컴포넌트에서 바로 DB를 호출할 수 있어 데이터 흐름을 설계할 때 단순해진다.
개인적으로 정리해본 사용 기준!
| 상황 | 선택 |
|---|---|
| UI 렌더링만 필요한 경우 | Server Component |
| DB나 파일 시스템 접근 | Server Component |
| 버튼 클릭, 입력 처리 등 | Client Component |
| 상태 관리 필요 | Client Component |
| 폼 제출 (간단) | Server Action + Server Component |
| 실시간 UX | Client + React Query / SWR |
마치며
RSC는 단순한 최적화 도구가 아니라, React 앱 구조를 다시 생각하게 만드는 변화라고 느꼈다. 가능하면 서버에서 렌더링하고, 정말 필요한 곳에만 클라이언트 컴포넌트를 두는 방식이 점차 익숙해지고 있다.
앞으로는 상태 관리와 렌더링 방식뿐 아니라, 컴포넌트가 어디서 실행될지까지 고려하는 능력이 필요해질 것이다.