1. 結論:なぜClient Componentにする必要があるのか?
Next.jsで localStorage、sessionStorage、window、document を使う際に 'use client'(Client Component)の指定が必要な理由は、これらが「ブラウザ(クライアント)にしか存在しない機能(ブラウザAPI)」だからです。
サーバー側で実行される「Server Component」の環境下では、これらのオブジェクトは存在しない(undefined)ため、アクセスした瞬間にエラーが発生します。
2. 仕組み:サーバー側とブラウザ側の「HTML組み立て」の違い
「サーバー側でHTMLを組み立てる(SSR)」と言っても、サーバー側とブラウザ側では、その裏側の仕組みが全く異なります。
| 比較項目 | サーバー側(Next.jsのSSR) | ブラウザ側(従来のJS / Hydration後) |
|---|---|---|
| 環境 | Node.js(サーバー環境) | Webブラウザ(Chrome/Safari等) |
| やっていること | JSXをただの「文字列(テキスト)」に変換 | 本物の「DOMオブジェクト」を生成 |
| 主要な手段 | React内部の文字列変換エンジン | document.createElement() などのDOM API |
| window / document | 存在しない | 存在する |
サーバー側の処理イメージ
サーバー側は、ブラウザのように画面を管理しているわけではありません。あなたが書いたJSXを、ただの長い文字列として結合しているだけです。
// 概念的なイメージ(実際はより複雑です)
let html = "";
html += "<div>";
html += "<h1>" + props.title + "</h1>";
html += "</div>";
return html; // 結果:"<div><h1>タイトル</h1></div>" という単なるテキストデータ
この段階ではただの「テキストの足し算」をしているだけなので、document オブジェクトは必要ありませんし、存在もしていません。
3. SSRから画面が表示されるまでのステップ(ライフサイクル)
-
【サーバー】文字列の組み立て
Next.jsがコンポーネントを解析し、HTMLの「文字列」を作成してブラウザへ送信します。
-
【ブラウザ】受信とHTML解析
ブラウザが届いたHTML文字列を読み込みます。この瞬間に初めて、ブラウザ内部に
windowやdocumentオブジェクトが生成され、画面に一瞬で文字や絵が表示されます(ただし、まだボタンなどは動きません)。 -
【ブラウザ】Hydration(ハイドレーション)
遅れて届いたJavaScriptがブラウザ上で実行され、すでに表示されているHTML(DOM)に対して、ボタンのクリックイベントなどの「動的な処理」を合体させます。
Next.jsの 'use client'(Client Component)とは、「上記ステップの『2』や『3』のタイミング(ブラウザ側)でも実行されるコードだよ」という宣言です。だからこそ、Client Componentにすることで安全に window や document にアクセスできるようになります。