프론트/리액트
문법) 'use client'를 작성하는 이유- 서버 컴포넌트, 클라이언트 컴포넌트
뽀짝코딩
2025. 6. 11. 12:24
728x90
'use client'는 Next.js App Router에서 클라이언트 컴포넌트임을 명시하는 지시문.
✅ 'use client'를 작성하는 이유
📌 1. 기본은 서버 컴포넌트이기 때문
Next.js(App Router 기준)에서는 .tsx 파일은 기본적으로 서버 컴포넌트이다.
→ 서버에서 실행되고, HTML을 생성해서 클라이언트에 전달한다.
하지만:
- 상태(useState)
- 이펙트(useEffect)
- 이벤트 핸들러 (onClick, onChange)
- 브라우저 API (localStorage, window 등)
이런 브라우저 전용 기능을 쓰려면 클라이언트 컴포넌트여야 한다.
📌 2. 'use client'가 필요할 때
아래 조건에 해당하면 컴포넌트 맨 위에 'use client'를 써야 한다
조건 예시
useState, useEffect, useRef 사용 시 | ✅ 리액트 훅 사용 |
onClick, onSubmit 등 이벤트 핸들러 사용 시 | ✅ 버튼 클릭 처리 등 |
브라우저 API 사용 시 | ✅ window, localStorage 등 |
상위 컴포넌트가 서버 컴포넌트인데, 이 컴포넌트는 클라이언트 기능을 써야 할 때 | ✅ props는 못 받더라도 내부에서 클라이언트 동작 필요할 때 |
✅**“상위 컴포넌트가 서버 컴포넌트이고, 프롭스로 값을 넘겨주지 않으면 ‘클라이언트로 따로 분리해서 써야 한다’”**
'use client'는 상위에서 props를 받지 않더라도, 내부에서 클라이언트 기능을 쓰면 반드시 필요!!
✅ 예시
❌ 아래는 오류남 (클릭 이벤트는 클라이언트에서만 동작하므로)
// app/some/page.tsx
export default function SomePage() {
return (
<button onClick={() => alert('hello')}>클릭</button>
);
}
- onClick 사용했는데 'use client'가 없어서 오류가 난다.
✅ 고치려면 이렇게:
'use client';
export default function SomePage() {
return (
<button onClick={() => alert('hello')}>클릭</button>
);
}
'use client'가 상위 컴포넌트로 자동 전파되지 않는 이유와
서버/클라이언트 컴포넌트 혼합 전략까지 간단히 정리 📘
✅ 'use client'는 왜 자동으로 상위에 전파되지 않나요?
👉 명확한 분리와 번들 크기 최소화를 위해서.
예시:
// ClientButton.tsx
'use client';
export default function ClientButton() {
return <button onClick={() => alert('hi')}>버튼</button>;
}
// ServerPage.tsx
export default function ServerPage() {
return <ClientButton />;
}
- 여기서 ServerPage는 서버 컴포넌트이고,
- ClientButton은 클라이언트 컴포넌트이다.
- 이 구조는 허용.
✅ 즉, 서버 컴포넌트가 클라이언트 컴포넌트를 자식으로 포함하는 것은 가능하지만,
그 반대는 불가능.
❌ 반대는 안 됨
// 'use client' 있음
'use client';
import ServerComponent from './ServerComponent';
export default function ClientPage() {
return <ServerComponent />; // ❌ 에러 발생 가능
}
클라이언트 컴포넌트에서 서버 컴포넌트를 직접 임포트하면 안 된다.
서버 컴포넌트는 Node.js 환경에서만 실행되므로, 브라우저에서 사용할 수 없기 때문.
✅ 서버/클라이언트 혼합 전략
목적 전략
초기 페이지 로딩 속도 최적화 | 최대한 서버 컴포넌트로 유지 (HTML 먼저 렌더링) |
클릭, 입력 등 인터랙션 필요 | 해당 부분만 클라이언트 컴포넌트로 분리 ('use client') |
클라이언트 전용 기능이 많음 | 전체 컴포넌트를 'use client' 처리하되, 서버 컴포넌트는 fetch로 데이터 전달 |
UI 분리 필요할 때 | components/ClientPart.tsx, components/ServerPart.tsx 식으로 나누기 |
💡 팁: 서버 컴포넌트 → 클라이언트 컴포넌트 프롭스로 데이터 넘기기
// ServerComponent.tsx
import ClientComponent from './ClientComponent';
export default async function ServerComponent() {
const data = await fetch(...).then(res => res.json());
return <ClientComponent data={data} />;
}
// ClientComponent.tsx
'use client';
export default function ClientComponent({ data }: { data: any }) {
return <div>{data.title}</div>;
}
참고
쳇지피티
반응형