ハイドレーションの崩壊とは?
Next.js(App Router)を使っていると、
「use client を付け忘れたらハイドレーションが崩壊した」
という現象に遭遇することがあります。
この記事では、これがなぜ起きるのかをわかりやすく解説します。
1. 前提:Next.js には 2 種類のコンポーネントがある
Server Component(デフォルト)
- Node.js 上で実行される
- ブラウザに JS を送らない
- データ取得に強い
- SSR になる
- Hooks(useState/useEffect)は使えない
Client Component("use client")
- ブラウザ側で実行される
- JS がバンドルされる
- Hooks や onClick が使える
- インタラクションに強い
- Server → Client の子は OK
- Client → Server の子は NG
この構造がキーになります。
2. 崩壊が起きるパターン
例えば Layout.tsx は Server Component とします。
Layout.tsx(Server)
└── Sidebar.tsx(本当は Client Component なのに "use client" が無い)
Sidebar.tsx にはこんなコードが入っているとします。
const [open, setOpen] = useState(false);
この時点で Sidebar は Client Component であるべきです。
しかし "use client" が無いと、Next.js は Sidebar を Server Component と誤認 します。
3. なぜハイドレーションが崩壊するのか?
Server Component として SSR を行った Sidebar を、
クライアント側が JS で再実行すると…
サーバー側
- useState 無し(実行できない)
- 静的な HTML に落ちる
クライアント側
- useState あり
- 動的な UI になる
サーバーとクライアントで描画結果が一致しない
→ Hydration failed の発生
Next.js はこれを検知すると、次の fallback を行います。
⚠「このツリーは正常にハイドレーションできない
→ クライアント側で全部レンダリングし直そう」
つまり 該当部分を含む上位構造が丸ごと CSR になる。
Layout 配下だった場合——
ページ全体が CSR になってしまうわけです。
4. 結果として起きる問題
- Hydration failed 警告
- SSR が効かない(パフォーマンス悪化)
- レイアウト全体が CSR に落ちる
- Flash of Unstyled Content (FOUC) が起きやすくなる
- useEffect/useState 前提の UI が壊れる
- App Router の恩恵がほぼ全部消える
5. 図で見てみる
正常系
ServerLayout
|--- ServerHeader
|--- ClientSidebar ← "use client"
|--- ServerContent
NG(use client 忘れ)
ServerLayout
|--- ServerHeader
|--- Sidebar(本当は Client)
|--- ServerContent
↓ Next.js の判断
⚠ 境界が壊れたので…
→ ServerLayout より下を全部 Client レンダリング扱いにする
→ Hydration mismatch
境界を壊すと「親ごと巻き込まれる」 のが最大のポイントです。
6. どう防ぐ?実践的チェックポイント
✓ 1. インタラクティブな UI には必ず "use client"
- ボタン
- モーダル
- サイドバー
- フォーム
- Hooks を使うコンポーネント
✓ 2. "use client" は UI 階層の最上位に一つだけ
子のファイルに重複で書く必要はない。
✓ 3. features/ui と app の境界をきれいにする
特に App Router の layout.tsx / page.tsx は
できる限り Server Component のまま保つのが正しい運用。
✓ 4. Server Component で useState/useEffect が出てきたら即 NG
7. まとめ
| 事象 | 理由 |
|---|---|
| "use client" を付け忘れるとハイドレーションが崩壊 | 本来 Client のはずのコンポーネントが Server と誤認され、SSR と CSR の描画が一致しなくなる |
| レイアウト全体が CSR になる | 問題のあるコンポーネントを含む上位ツリーごとクライアントレンダリングに切り替わるため |
| 防ぐには? | インタラクティブ UI は必ず "use client"、App Router のページはなるべく Server のまま運用 |