useState を import できないエラー
実際に出るエラー
Server Component のファイルから useState などのフックを import したときに出るビルドエラーです。
#何が起きているか
App Router のファイルは、既定で Server Component として解決されます。useState はブラウザ側の状態を扱う API なので、Server Component のモジュールからは import できません。
重要なのは、**エラーが出るのは「使った場所」ではなく「import したモジュール」**だという点です。エラー文も "importing a module that depends on useState" と書いています。自分では useState を書いていなくても、間接的に依存しているものを import しただけで同じエラーになります。
これは描画より前、モジュールを解決する段階で検出されます。だから next build も next dev も、ページを開く前に止まります。
#原因はほぼこの3つ
1. 'use client' を書き忘れている
いちばん多い形です。
// app/counter/page.tsx
import { useState } from 'react' // ← 先頭に 'use client' が無い
export default function Page() {
const [n, setN] = useState(0)
return <button onClick={() => setN(n + 1)}>{n}</button>
}
2. 'use client' の位置が間違っている
ファイルのいちばん先頭でなければ効きません。import の後ろに書いても無効です。コメントより前である必要はありませんが、import 文より前に置いてください。
3. import したライブラリが内部でフックを使っている
自分のコードにフックが1つも無いのに出る場合は、これです。UI ライブラリ、フォームライブラリ、アニメーションライブラリなどが該当します。
#最短の確認手順
- エラー文に出ているファイル名を開く
- 1行目が
'use client'かどうかを見る - 違うなら、そのファイルは Server Component
- 自分のコードにフックが無い場合は、import 文を上から順に疑う
#直し方
推奨:フックを使う部品だけを切り出す
ページ全体に 'use client' を付けるのではなく、状態を持つ部分だけを別ファイルにします。
// components/Counter.tsx
'use client'
import { useState } from 'react'
export function Counter() {
const [n, setN] = useState(0)
return <button onClick={() => setN(n + 1)}>{n}</button>
}
// app/counter/page.tsx(Server Component のまま)
import { Counter } from '@/components/Counter'
export default async function Page() {
const title = await getTitle() // サーバー側でデータを取れる
return (
<>
<h1>{title}</h1>
<Counter />
</>
)
}
こうすると、ブラウザへ送られる JavaScript はカウンターの分だけで済みます。
ライブラリが原因の場合
そのライブラリを使う部分を、'use client' を書いた薄いファイルで包みます。
// components/Chart.tsx
'use client'
export { Chart } from 'some-chart-library'
#なぜページ全体に付けてはいけないのか
'use client' は「ここから下をブラウザにも送る」という宣言です。ページの先頭に書くと、そのページが import しているものすべてが対象になります。
- 表示するだけの部分まで JavaScript がブラウザへ送られる
- DB やサーバー専用の処理を、そのファイルから直接呼べなくなる
付けるほど重くなるので、置く場所はできるだけ葉に近い側です。
#開発中に出るのか
出ます。これは描画前の解決段階で検出されるので、next dev でもそのページに移動した時点で止まります。本番だけで出るタイプのエラーではありません。
#再発防止
- フックを使うファイルは、作った瞬間に
'use client'を書く - 逆に、
'use client'を書いたファイルには「ブラウザが必要な処理」しか置かない - 新しいライブラリを入れたら、Server Component から使えるかを最初に確かめる
#関連するエラー
window や document を Server Component で参照した場合は、ビルドではなく描画の段階で別のエラーになります。
ReferenceError: window is not defined
こちらは import では検出できないので、実際に描画されるまで出ません。