Next.js의 App Router에서는 컴포넌트를 서버 컴포넌트와 클라이언트 컴포넌트로 구분한다.
이 구분은 상호작용 유무와 렌더링 위치에 따라 이루어진다.
Client Component
클라이언트 컴포넌트는 브라우저에서 실행되며, 사용자와의 상호작용을 처리할 수 있다.
'use client' // 파일 최상단에 지시어 선언
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
- 사전 렌더링 시 한 번, 하이드레이션 시 한 번, 총 두 번 실행
useState,useEffect등의 React 훅 사용 가능- 브라우저 API에 접근 가능
Server Component
서버 측에서 사전 렌더링을 진행할 때만 딱 한 번 실행되며, 앱라우터는 기본적으로 서버 컴포넌트로 설정되어 있다.
- 서버에서만 실행되며, 클라이언트로 전송되는 JS 번들에 포함되지 않음 ->하이드레이션 작업 속도 향상
- 상호작용이 필요 없는 정적인 컴포넌트에 적합
- 데이터베이스나 파일 시스템에 직접 접근 가능
Next.js 공식 문서에서는 페이지의 대부분을 서버 컴포넌트로 구성하고, 클라이언트 컴포넌트는 꼭 필요한 경우에만 사용할 것을 권장하고 있다.
주의 사항
1. 서버 컴포넌트 제한 사항
서버 컴포넌트에는 브라우저에서 실행될 코드가 포함되면 안된다.
- React 훅, 이벤트 핸들러, 브라우저 기능 등 ❌
2. 클라이언트 컴포넌트 실행 환경
클라이언트 컴포넌트는 클라이언트에서만 실행되지 않는다.
"use client";
export default function Home() {
console.log("컴포넌트 실행!"); // 서버에서 한 번, 클라이언트에서 한 번 출력
return <div>인덱스 페이지</div>;
}
3. 컴포넌트 간 import 제한
클라이언트 컴포넌트에서 서버 컴포넌트를 import 할 수 없다.
Next.js가 자동으로 서버 컴포넌트를 클라이언트 컴포넌트로 변경하기 때문이다.
"use client";
import Servercomponent from "./server-component.tsx"; // ❌
export default function ClientComponent() {
return <Servercomponent />;
}
// 지시어 없이 서버 컴포넌트로 작성했지만,
// 클라이언트 컴포넌트에서 import되면 클라이언트 컴포넌트로 변경됨
export default function Servercomponent() {
return <div>서버 컴포넌트</div>;
}
다만, 다음과 같은 방식으로 서버 컴포넌트를 클라이언트 컴포넌트의 자식으로 전달할 수 있다.
// 서버 컴포넌트
export default function ServerComponent() {
console.log("서버 컴포넌트");
return <div></div>;
}
// 클라이언트 컴포넌트
"use client";
import { ReactNode } from "react";
export default function ClientComponent({ children }: { children: ReactNode }) {
console.log("클라이언트 컴포넌트");
return <div>{children}</div>;
}
// 페이지 컴포넌트
import ClientComponent from "./client-component";
import ServerComponent from "./server-component";
import styles from "./page.module.css";
export default function Home() {
return (
<div>
<ClientComponent>
<ServerComponent />
</ClientComponent>
</div>
);
}
4. Props 전달 제한
서버 컴포넌트에서 클라이언트 컴포넌트에게 직렬화 되지 않는 Props는 전달할 수 없다.
직렬화 (Serialization)
객체, 배열, 클래스 등의 복잡한 구조의 데이터를 네트워크 상으로 전송하기 위해 아주 단순한 형태(문자열, Byte)로 변환하는 것
예시:
// 직렬화 전
const person = {
name: "woodstock",
favoritNumber: 5,
};
// 직렬화 후
{"name":"woodstock","favoritNumber":5}
// 함수는 직렬화가 불가능
function func() {
console.log("함수는 직렬화 X");
}
렌더링 과정과 RSC Payload
1. 사전 렌더링 과정
- 페이지를 구성하는 모든 컴포넌트 중 서버 컴포넌트들만 먼저 실행
- 이 과정에서 RSC Payload가 생성됨
2. RSC Payload (React Server Component Payload)
- 서버 컴포넌트의 순수한 데이터(결과물)이자, 서버 컴포넌트를 직렬화한 결과
- 포함되는 정보:
- 서버 컴포넌트의 렌더링 결과
- 연결된 클라이언트 컴포넌트의 위치
- 클라이언트 컴포넌트에게 전달하는 Props 값
3. 클라이언트 컴포넌트 실행
- 서버 컴포넌트 실행 후, 클라이언트 컴포넌트가 실행됨
- RSC Payload와 클라이언트 컴포넌트 실행 결과가 합쳐져 최종 HTML 페이지가 완성됨
'Frontend > Next.js' 카테고리의 다른 글
| 데이터 캐시와 리퀘스트 메모이제이션 (0) | 2025.11.13 |
|---|---|
| Next.js의 데이터 페칭 방식 (0) | 2025.11.13 |
| Next.js 검색 엔진 최적화 (SEO) (0) | 2025.11.13 |
| Next.js 페이지 라우터의 렌더링 방식 (0) | 2025.11.13 |
| Next.js의 프리 페칭 (Pre-fetching) (0) | 2025.11.13 |
