Next.js開発でちょいちょい発生する、ハイドレーションエラーの原因と対策を紹介

ReactやNext.jsで開発していると、一度は遭遇するであろうハイドレーションエラー。
見た目には問題ないのに、コンソールにエラーが出て不安になる…そんな経験はありませんか?
ハイドレーションエラーは、サーバーサイドレンダリング(SSR)とクライアントサイドの描画結果に差異がある場合に発生します。
本記事では、そのメカニズムと原因、そして再発させないための具体的な対策を、初心者にもわかりやすく整理しました。
ハイドレーションエラーの発生原因
ハイドレーションとは、SSRで描画されたHTMLに対してクライアント側でReactがイベントバインドなどを行うプロセスのこと。
この際、サーバーで生成されたHTMLとクライアントでのJSによる描画結果が一致しない場合に、次のようなエラーが出力されます。
arduinoWarning: Text content did not match. Server: "Hello" Client: "Hi"
原因となる具体例は以下の通りです:
原因 | 説明 | 例 |
---|---|---|
クライアント限定APIの使用 | window やnavigator など、SSR時に存在しないオブジェクトを利用 | useEffect 外でwindow.innerWidth を参照 |
ランダム値の使用 | SSRとCSRで異なる値になる | Math.random() やDate.now() の直接使用 |
状態の非同期取得 | クライアントでのみデータを取得してUIを更新する | 初期表示がloading 、CSR後にデータ になる差異 |
時刻やロケールに依存 | タイムゾーンやIntl により描画が変化 | 日付のローカライズ表示など |
ハイドレーションエラーを防ぐための対策
ハイドレーションエラーを避けるためには、サーバーとクライアントで同じHTMLを出力することが鉄則です。
以下に具体的な対策を紹介します。
1. クライアント限定処理はuseEffect
内に記述
ReactのuseEffect
はクライアント実行時のみ動作します。
window
などのブラウザAPIを使用する場合は、必ずこの中で処理しましょう。
tsxconst [width, setWidth] = useState(0);
useEffect(() => {
setWidth(window.innerWidth);
}, []);
2. ランダム・時刻系の値はSSR側でも揃える
例えばDate.now()
を直接使わず、getServerSideProps
やgetStaticProps
で生成し、Propsとして渡すようにします。
tsxexport const getServerSideProps = () => {
return {
props: {
timestamp: Date.now(),
},
};
};
3. dynamic()
を使ってクライアントのみレンダリング
どうしてもSSRで描画したくないコンポーネントは、next/dynamic
でクライアント限定に。
tsximport dynamic from 'next/dynamic';
const ClientOnlyComponent = dynamic(() => import('./ClientOnlyComponent'), {
ssr: false,
});
4. 条件付きレンダリングで安全確認
typeof window !== "undefined"
のようなチェックを使い、SSR時の実行を防ぐ工夫も効果的です。
tsx{typeof window !== "undefined" && <ClientOnlyComponent />}
まとめ:Next.jsではSSRとCSRの一貫性が鍵
ハイドレーションエラーは、見た目に影響が出ないことも多いため軽視されがちですが、SEOやパフォーマンス、アクセシビリティに悪影響を与える可能性があります。
ハイドレーションの原理と原因を正しく理解し、以下のポイントを抑えて開発を進めましょう。
- SSRとCSRで出力を一致させる
- クライアント専用処理は
useEffect
へ - 不安定な値(日時、乱数、ブラウザAPI)はSSR中に扱わない
dynamic()
でSSRを明示的に制御
これらを意識するだけで、Next.jsでの開発がより安定し、安心してスケールするアプリケーションを構築できます。
記事Article
もっと見る- article
React.memoとは?再レンダリングを防ぐための基本と使い方をわかりやすく解説
- article
Reactの再レンダリングを制御する!memo・useMemo・useCallbackの使い分けを紹介
- article
Reactの状態管理2025:「useState」「Redux Toolkit」「Jotai」「Zustand」を比較してみた
- article
Next.jsでの画像最適化戦略:next/image vs 外部CDNを比較してみた
- article
React Server Componentsの可能性と課題を実用に向けて考えてみる
- article
Next.js 13 App Router入門:Pages Routerとの違いと移行のコツをわかりやすく紹介