T-CREATOR

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

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

ReactやNext.jsで開発していると、一度は遭遇するであろうハイドレーションエラー
見た目には問題ないのに、コンソールにエラーが出て不安になる…そんな経験はありませんか?

ハイドレーションエラーは、サーバーサイドレンダリング(SSR)とクライアントサイドの描画結果に差異がある場合に発生します。
本記事では、そのメカニズムと原因、そして再発させないための具体的な対策を、初心者にもわかりやすく整理しました。


ハイドレーションエラーの発生原因

ハイドレーションとは、SSRで描画されたHTMLに対してクライアント側でReactがイベントバインドなどを行うプロセスのこと。
この際、サーバーで生成されたHTMLとクライアントでのJSによる描画結果が一致しない場合に、次のようなエラーが出力されます。

arduinoWarning: Text content did not match. Server: "Hello" Client: "Hi"

原因となる具体例は以下の通りです:

原因説明
クライアント限定APIの使用windownavigatorなど、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()を直接使わず、getServerSidePropsgetStaticPropsで生成し、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

もっと見る