
Next.js App Router 환경에서 아래와 같은 에러가 발생했다.
You're importing a component that needs `useState`.
This React Hook only works in a Client Component.
To fix, mark the file (or its parent) with the "use client" directive.
에러가 발생한 코드는 다음과 같았다.
import { useState } from "react";
export default function Nav() {
const [active, setActive] = useState("10대");
return <div>Nav</div>;
}
단순히 useState를 사용했을 뿐인데, 빌드 에러가 발생했다.
이 문제의 핵심은 Next.js App Router의 기본 동작 방식 때문이다.
App Router에서 작성하는 컴포넌트는 기본적으로 Server Component이다.
Server Component는 서버에서만 실행되고, 따라서 아래 기능들을 사용할 수 없다
- useState, useEffect
- onClick, onChange 등등의 이벤트 핸들러
- 브라우저 API (window, document 등)
즉, useState는 브라우저에서만 동작하는 React Hook인데 Server Component에서 사용했기 때문에 에러가 발생한 것이다.
아래는 Server Component와 Client Component를 비교하는 표이다.
| 구분 | Server Component | Client Component |
|---|---|---|
| 기본 여부 | 기본값 | 명시 필요 |
| useState | ❌ | ✅ |
| 이벤트 처리 | ❌ | ✅ |
| 렌더링 위치 | 서버 | 브라우저 |
그래서 상태나 이벤트가 필요한 컴포넌트는 반드시 Client Component여야 한다.
해결 방법은 아주 간단한데 그냥 파일 최상단에 "use client"를 추가해주면 된다.
"use client";
import { useState } from "react";
export default function Nav() {
const [active, setActive] = useState("10대");
return <div>Nav</div>;
}
중요한 점은 반드시 파일 최상단, import보다 위에 있어야 한다는 것이다.
import { useState } from "react";
"use client";
이렇게 작성하면 인식되지 않는다.
Next.js는 파일을 읽을 때 맨 처음에 "use client"가 있는지 보고 이 파일을 Client Component로 변환할지 결정한다.
즉, "use client"는 일반 문자열이 아니라 Next.js에게 주는 컴파일 지시자이다.
그래서 import 이후에 작성하면 이미 Server Component로 판단된 뒤라 의미가 없어지는 것이다.
Nav.tsx에 "use client"가 있으면 그 아래에서 import되는 컴포넌트들은 자동으로 Client Component가 된다. 그러므로 하위 컴포넌트에 "use client"를 중복해서 쓸 필요는 없다