본문 바로가기
C.W.K.
Stream
Lesson 03 of 08 · published

브라우저가 필요할 때만 클라이언트 컴포넌트

~20 min · use client, interactivity, hooks

Level 0호기심
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

상호작용 경계를 선언해

상태, 이벤트, ref, 브라우저 API가 필요하거나 Framer Motion, Headless UI, React Hook Form처럼 hook에 기대는 라이브러리를 쓸 때는 파일 첫 줄에 'use client'를 적어. 이 선언이 서버 트리 안에서 브라우저가 맡을 경계를 만들어.

선언은 import 그래프를 따라 퍼져

'use client'는 그 파일 하나에만 붙는 딱지가 아니야. 그 파일이 import한 모듈들도 클라이언트 번들에 들어가. 그래서 페이지나 레이아웃 꼭대기에 붙이면 필요 없는 하위 코드까지 모두 브라우저로 보내게 돼. 선언은 가능한 한 상호작용이 있는 잎에 가까이 둬.

필요한 것실행 위치
useState, useEffect, useRef클라이언트
onClick, onChange, onSubmit클라이언트
window, document, localStorage클라이언트
hook 기반 외부 UI 라이브러리클라이언트
평범한 데이터 표시서버
데이터 fetch와 DB 조회서버
비밀값 읽기서버
무거운 데이터 가공서버

서버 컴포넌트가 클라이언트 컴포넌트를 그리는 건 괜찮아. 경계를 넘겨야 할 값만 직렬화할 수 있으면 돼.

use client 파일이 import하는 목록을 코드 리뷰에서 함께 봐. 작은 토글이 거대한 chart와 데이터 도구를 끌고 오면 상호작용 잎을 더 작게 분리해. 서버 부모가 초기 값과 서버에서 렌더링한 children을 내려 주면 기능을 유지하면서 클라이언트 경계를 낮출 수 있어. 클라이언트 경계를 옮길 때는 기능만 보지 말고 번들에 새로 딸려오는 import도 비교해. 작은 상호작용 하나가 무거운 라이브러리 전체를 끌고 오면 경계가 너무 높은 거야. 클라이언트 컴포넌트도 첫 화면에서는 서버에서 미리 렌더링될 수 있어. 이름이 “클라이언트”라고 HTML이 브라우저에서만 생기는 건 아니야. 차이는 상호작용을 위해 코드가 브라우저로 전송되고 hydration된다는 점이니, 표시 위치와 실행 번들을 구분해. use client를 페이지 꼭대기와 작은 잎에 각각 두고 bundle analyzer 결과를 저장해. 외부 hook 라이브러리와 서버 children이 어느 chunk에 포함되는지 보고, 선언을 지웠을 때 이벤트와 브라우저 API가 빌드 단계에서 제대로 실패하는지도 확인해.

Code

최소 클라이언트 컴포넌트·tsx
'use client';
import { useState } from 'react';

export function Counter({ initial = 0 }: { initial?: number }) {
  const [count, setCount] = useState(initial);
  return (
    <button
      onClick={() => setCount(c => c + 1)}
      className="rounded bg-blue-600 px-3 py-1 text-white"
    >
      {count}
    </button>
  );
}
서버 부모가 클라이언트 잎을 렌더링하기·tsx
// app/page.tsx — 서버 컴포넌트
import { Counter } from '@/components/Counter';

export default async function Page() {
  const initial = await fetch('https://api.example.com/count').then(r => r.json());
  return <Counter initial={initial.value} />;
}

External links

Exercise

서버에서 렌더링할 수 있는 트리를 감싼 클라이언트 컴포넌트를 찾아. 'use client'를 실제 상호작용 잎으로 내리고 주변 모듈이 클라이언트 bundle에서 빠지는지 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.