Next.js App Router를 처음 배우면 use client를 언제 사용해야 하는지 헷갈릴 수 있습니다.
결론부터 말하면, 브라우저에서 동작해야 하는 기능이 있을 때만 use client를 사용합니다.
Next.js App Router에서는 기본적으로 컴포넌트가 Server Component로 동작합니다. 따라서 모든 파일에 use client를 붙일 필요는 없습니다.
use client란?
use client는 파일 최상단에 작성합니다.
'use client';
export default function Button() {
return <button>클릭</button>;
}
이 코드는 Next.js에게 다음과 같이 알려줍니다.
이 컴포넌트는 브라우저에서 실행되어야 합니다.
즉, use client는 Server Component와 Client Component를 구분하는 기준입니다.
기본은 Server Component다
Next.js App Router에서는 use client를 붙이지 않으면 기본적으로 Server Component입니다.
export default function Page() {
return (
<main>
<h1>상품 상세 페이지</h1>
<p>상품 정보를 보여줍니다.</p>
</main>
);
}
이 컴포넌트는 단순히 화면만 보여줍니다.
상태 관리나 클릭 이벤트가 없기 때문에 use client가 필요하지 않습니다.
서버에서 데이터를 가져와 화면에 보여주는 경우도 보통 Server Component가 적합합니다.
export default async function PostsPage() {
const res = await fetch('https://example.com/api/posts');
const posts = await res.json();
return (
<main>
<h1>게시글 목록</h1>
{posts.map((post: any) => (
<p key={post.id}>{post.title}</p>
))}
</main>
);
}
use client가 필요한 경우
다음 기능을 사용한다면 use client가 필요합니다.
- useState
- useEffect
- onClick, onChange 같은 이벤트
- window, document, localStorage
- 브라우저에서만 동작하는 라이브러리
- 모달, 탭, 드롭다운, 슬라이더 같은 인터랙션 UI
예를 들어 클릭할 때 숫자가 증가하는 버튼은 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와 onClick은 브라우저에서 동작해야 하므로 use client가 필요합니다.
브라우저 기능을 사용할 때도 필요합니다
window, document, localStorage는 브라우저에만 존재합니다.
서버에는 이런 객체가 없기 때문에 Server Component에서는 사용할 수 없습니다.
'use client';
import { useEffect } from 'react';
export default function VisitSave() {
useEffect(() => {
localStorage.setItem('visited', 'true');
}, []);
return <p>방문 기록을 저장했습니다.</p>;
}
이처럼 브라우저 전용 기능을 사용할 때는 use client를 붙여야 합니다.
추천 사용 방식
초보자가 자주 하는 실수는 페이지 전체에 use client를 붙이는 것입니다.
'use client';
export default function ProductPage() {
return (
<main>
<h1>상품 상세</h1>
<button>장바구니 담기</button>
</main>
);
}
이렇게 하면 페이지 전체가 Client Component가 됩니다.
하지만 실제로 브라우저 기능이 필요한 부분은 버튼뿐일 수 있습니다.
더 좋은 방식은 버튼만 따로 분리하는 것입니다.
// app/products/page.tsx
import AddToCartButton from './AddToCartButton';
export default function ProductPage() {
return (
<main>
<h1>상품 상세</h1>
<p>상품 설명입니다.</p>
<AddToCartButton />
</main>
);
}
// app/products/AddToCartButton.tsx
'use client';
export default function AddToCartButton() {
function handleClick() {
alert('장바구니에 담았습니다.');
}
return <button onClick={handleClick}>장바구니 담기</button>;
}
이렇게 하면 페이지는 Server Component로 유지하고, 클릭이 필요한 버튼만 Client Component로 만들 수 있습니다.
물론 페이지 전체에 use client를 붙이는 건 임시 처리 방법에 가깝습니다. 따라서 내일만 보기보다는, 이런 문제는 빠른 시일 내에 client, server를 확실히 분리하는 것이 좋습니다.
즉 use client는 다음 상황에서 사용합니다.
1. useState, useEffect를 사용할 때
2. onClick, onChange 같은 이벤트를 사용할 때
3. window, document, localStorage를 사용할 때
4. 브라우저 전용 라이브러리를 사용할 때
5. 사용자 조작이 필요한 UI를 만들 때
반대로 단순히 화면을 보여주거나 서버에서 데이터를 가져오는 컴포넌트라면 use client를 붙이지 않아도 됩니다.
핵심은 다음과 같습니다.
기본은 Server Component로 작성합니다.
브라우저 기능이 필요한 작은 컴포넌트에만 use client를 사용합니다.
이 기준을 지키면 Next.js App Router 구조를 더 깔끔하고 효율적으로 만들 수 있습니다.