Deprecated

この API は、今後のメジャーバージョンの React で削除される予定です。

React 18 では、hydrate は hydrateRoot に置き換えられました。React 18 で hydrate を使用すると、アプリは React 17 を実行しているかのような振る舞いになるとの警告が表示されます。詳細はこちらをご覧ください。

hydrate を使用すると、React 17 以前の react-dom/server によって事前生成した HTML コンテンツが含まれるブラウザ DOM ノード内に、React コンポーネントを表示できます。

hydrate(reactNode, domNode, callback?)

リファレンス

hydrate(reactNode, domNode, callback?)

React 17 以前の環境で hydrate を呼び出して、サーバ環境で事前に React がレンダーした HTML に対して React を「アタッチ」します。

import { hydrate } from 'react-dom';

hydrate(reactNode, domNode);

React は、domNode 内に存在する HTML にアタッチし、その内部の DOM の管理を引き継ぎます。React で完全に構築されたアプリには、ルートコンポーネントを引数にした hydrate 呼び出しが通常 1 つのみ存在します。

さらに例を見る

引数

  • reactNode: 既存の初期 HTML をレンダーするのに使用された “React ノード”。これは通常、ReactDOM Server のメソッド(例:React 17 の renderToString(<App />))でレンダーされた JSX、例えば <App /> になります。

  • domNode: サーバ上でルート要素としてレンダーされた DOM 要素。

  • 省略可能 callback: 関数。渡された場合、React はコンポーネントのハイドレーション後にそれを呼び出します。

返り値

hydrate は null を返します。

注意点

  • hydrate は、レンダーされたコンテンツが、サーバでレンダーされたコンテンツと同一であることを期待しています。React はテキストコンテンツの差異を修正できますが、不一致はバグとして扱い修正する必要があります。
  • 開発モードでは、React はハイドレーション中の不一致について警告します。不一致が発生した場合、属性の違いが修正される保証はありません。これはパフォーマンス上の理由から重要です。なぜならほとんどのアプリでは、不一致はまれであり、すべてのマークアップを検証することは非常に高コストになるからです。
  • アプリには通常、hydrate 呼び出しは 1 つだけ存在します。フレームワークを使用している場合、フレームワークがこの呼び出しを行うかもしれません。
  • アプリがクライアントでレンダーする形式であり、事前レンダーされた HTML がない場合、hydrate() は使用できません。代わりに、React 17 以前では render()、React 18 以降では createRoot() を使用してください。

使用法

hydrate を呼び出して、React コンポーネントをサーバでレンダーされたブラウザの DOM ノードにアタッチします。

import { hydrate } from 'react-dom';

hydrate(<App />, document.getElementById('root'));

hydrate() を使用して、クライアントのみのアプリ(サーバでレンダーされた HTML がないアプリ)をレンダーすることはサポートされていません。代わりに、React 17 以前では render()、React 18 以降では createRoot() を使用してください。

サーバでレンダーされた HTML のハイドレーション

React では、“ハイドレーション (hydration)” とは、サーバ環境の React によって事前レンダーされている HTML に React が「アタッチ」することを指します。ハイドレーション中、React は既存のマークアップにイベントリスナをアタッチし、アプリのレンダー処理をクライアントに引き継ぎます。

React で完全に構築されたアプリでは、通常、アプリ全体の起動時に 1 つの「ルート」のハイドレーションを一度だけ行います。

import './styles.css';
import { hydrate } from 'react-dom';
import App from './App.js';

hydrate(<App />, document.getElementById('root'));

通常、hydrate を再度呼び出したり、複数の場所で呼び出したりする必要はありません。ここから先は、React がアプリケーションの DOM を管理しています。UI を更新するには、コンポーネントは state を使うことになるでしょう。

ハイドレーションに関する詳細は、hydrateRoot のドキュメントを参照してください。


やむを得ないハイドレーション不一致エラーの抑制

サーバとクライアントの間で、単一の要素の属性やテキストコンテンツがやむを得ない理由で異なる場合(たとえば、タイムスタンプなど)、ハイドレーションの不一致警告を抑制することができます。

要素のハイドレーション警告を抑制するには、suppressHydrationWarning={true} を追加します。

export default function App() {
  return (
    <h1 suppressHydrationWarning={true}>
      Current Date: {new Date().toLocaleDateString()}
    </h1>
  );
}

これは単一レベルの深さまでしか機能せず、避難ハッチとしての使用を意図しています。過度に使用しないでください。これを使用してもテキストコンテンツ以外の場合は React は違いを修正しようとはしないため、将来の更新まで一貫性が保たれない可能性があります。


クライアントとサーバで異なるコンテンツの処理

サーバとクライアントで意図的に異なるものをレンダーする必要がある場合、2 回に分けたレンダーを行うことができます。クライアントで異なるものをレンダーするコンポーネントは、isClient のような state 変数を読み取るようにし、この変数をエフェクト内で true に設定することができます。

import { useState, useEffect } from "react";

export default function App() {
  const [isClient, setIsClient] = useState(false);

  useEffect(() => {
    setIsClient(true);
  }, []);

  return (
    <h1>
      {isClient ? 'Is Client' : 'Is Server'}
    </h1>
  );
}

この方法では、初回のレンダーはサーバと同じコンテンツをレンダーし、不一致を回避しますが、追加のレンダーがハイドレーションの直後に同期的に行われます。

落とし穴

このアプローチではコンポーネントを 2 回レンダーする必要があるためハイドレーションが遅くなります。低速な接続におけるユーザ体験に注意してください。JavaScript コードは初期レンダーされた HTML よりもかなり遅く読み込まれる場合があるため、ハイドレーション直後に異なる UI をレンダーするとユーザに不快感を与えるかもしれません。