hydrateRoot
は、以前にreact-dom/server
によって生成されたHTMLコンテンツを持つブラウザDOMノード内にReactコンポーネントを表示できるようにします。
const root = hydrateRoot(domNode, reactNode, options?)
リファレンス
hydrateRoot(domNode, reactNode, options?)
hydrateRoot
を呼び出して、サーバー環境でReactによって既にレンダリングされた既存のHTMLにReactを「アタッチ」します。
import { hydrateRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, reactNode);
Reactは、domNode
内にあるHTMLにアタッチし、その中のDOMの管理を引き継ぎます。Reactで完全に構築されたアプリは、通常、ルートコンポーネントで1つのhydrateRoot
呼び出しのみを持ちます。
パラメータ
-
domNode
: サーバーでルート要素としてレンダリングされたDOM要素。 -
reactNode
: 既存のHTMLをレンダリングするために使用される「Reactノード」。これは通常、<App />
のようなJSXの一部であり、renderToPipeableStream(<App />)
のようなReactDOM Server
メソッドでレンダリングされました。 -
オプション
options
: このReactルートのオプションを持つオブジェクト。- オプション
onCaughtError
: Reactがエラー境界でエラーをキャッチしたときに呼び出されるコールバック。エラー境界でキャッチされたerror
と、componentStack
を含むerrorInfo
オブジェクトとともに呼び出されます。 - オプション
onUncaughtError
: エラーがスローされ、エラー境界で捕捉されなかった場合に呼び出されるコールバック。スローされたerror
と、componentStack
を含むerrorInfo
オブジェクトとともに呼び出されます。 - オプション
onRecoverableError
: Reactが自動的にエラーから回復したときに呼び出されるコールバック。Reactがスローするerror
と、componentStack
を含むerrorInfo
オブジェクトとともに呼び出されます。一部の回復可能なエラーには、元のエラーの原因がerror.cause
として含まれる場合があります。 - オプション
identifierPrefix
: ReactがuseId
によって生成されるIDに使用する文字列プレフィックス。同じページで複数のルートを使用する場合の競合を避けるのに役立ちます。サーバーで使用したものと同じプレフィックスである必要があります。
- オプション
以下の値を返します
hydrateRoot
は、2つのメソッドを持つオブジェクトを返します。render
とunmount
です。
注意事項
hydrateRoot()
は、レンダリングされたコンテンツがサーバーでレンダリングされたコンテンツと同一であることを期待します。不一致はバグとして扱い、修正する必要があります。- 開発モードでは、Reactはハイドレーション中の不一致について警告します。不一致が発生した場合、属性の違いがパッチされる保証はありません。ほとんどのアプリでは不一致がまれであり、すべてのマークアップを検証すると非常にコストがかかるため、これはパフォーマンス上の理由で重要です。
- アプリ内では
hydrateRoot
の呼び出しは1回のみになるでしょう。フレームワークを使用している場合は、この呼び出しをフレームワークが行う場合があります。 - アプリがクライアント側でレンダリングされ、HTMLがまだレンダリングされていない場合は、
hydrateRoot()
の使用はサポートされていません。代わりにcreateRoot()
を使用してください。
root.render(reactNode)
root.render
を呼び出して、ブラウザのDOM要素のハイドレートされたReactルート内のReactコンポーネントを更新します。
root.render(<App />);
Reactは、ハイドレートされたroot
内の<App />
を更新します。
パラメータ
reactNode
: 更新したい "Reactノード"。これは通常、<App />
のようなJSXですが、createElement()
で構築されたReact要素、文字列、数値、null
、またはundefined
を渡すこともできます。
以下の値を返します
root.render
は、undefined
を返します。
注意事項
- ルートのハイドレーションが完了する前に
root.render
を呼び出すと、Reactは既存のサーバーでレンダリングされたHTMLコンテンツをクリアし、ルート全体をクライアントレンダリングに切り替えます。
root.unmount()
Reactルート内のレンダリングされたツリーを破棄するには、root.unmount
を呼び出します。
root.unmount();
Reactで完全に構築されたアプリでは、通常、root.unmount
を呼び出すことはありません。
これは、ReactルートのDOMノード(またはその祖先のいずれか)が他のコードによってDOMから削除される可能性がある場合に主に役立ちます。たとえば、非アクティブなタブをDOMから削除するjQueryのタブパネルを想像してください。タブが削除されると、その内部にあるすべてのもの(内部のReactルートを含む)もDOMから削除されます。 root.unmount
を呼び出して、Reactに削除されたルートのコンテンツの管理を「停止」するように指示する必要があります。そうしないと、削除されたルート内のコンポーネントは、サブスクリプションなどのリソースをクリーンアップして解放しません。
root.unmount
を呼び出すと、ルート内のすべてのコンポーネントがアンマウントされ、ツリー内のイベントハンドラーや状態の削除を含め、ReactがルートDOMノードから「切り離され」ます。
パラメータ
root.unmount
はパラメータを受け入れません。
戻り値
root.unmount
はundefined
を返します。
注意点
-
root.unmount
を呼び出すと、ツリー内のすべてのコンポーネントがアンマウントされ、ReactがルートDOMノードから「切り離され」ます。 -
root.unmount
を呼び出すと、そのルートで再びroot.render
を呼び出すことはできません。アンマウントされたルートでroot.render
を呼び出そうとすると、「アンマウントされたルートを更新できません」というエラーがスローされます。
使用法
サーバーでレンダリングされたHTMLのハイドレーション
アプリのHTMLがreact-dom/server
によって生成された場合、クライアント側でハイドレーションする必要があります。
import { hydrateRoot } from 'react-dom/client';
hydrateRoot(document.getElementById('root'), <App />);
これにより、アプリのブラウザDOMノード内のサーバーHTMLがアプリのReactコンポーネントでハイドレートされます。通常、これは起動時に一度だけ実行します。フレームワークを使用している場合は、バックグラウンドでこれが行われる可能性があります。
アプリをハイドレートするために、Reactはサーバーから生成された初期HTMLにコンポーネントのロジックを「アタッチ」します。ハイドレーションは、サーバーからの初期HTMLスナップショットを、ブラウザで実行される完全にインタラクティブなアプリに変換します。
import './styles.css'; import { hydrateRoot } from 'react-dom/client'; import App from './App.js'; hydrateRoot( document.getElementById('root'), <App /> );
hydrateRoot
を再度呼び出す必要も、複数の場所で呼び出す必要もありません。この時点から、ReactがアプリケーションのDOMを管理します。UIを更新するために、コンポーネントは代わりにステートを使用します。
ドキュメント全体のハイドレーション
Reactで完全に構築されたアプリは、<html>
タグを含む、ドキュメント全体をJSXとしてレンダリングできます。
function App() {
return (
<html>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/styles.css"></link>
<title>My app</title>
</head>
<body>
<Router />
</body>
</html>
);
}
ドキュメント全体をハイドレートするには、hydrateRoot
の最初の引数として、document
グローバルを渡します。
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(document, <App />);
回避不可能なハイドレーションの不一致エラーの抑制
単一の要素の属性またはテキストコンテンツが、サーバーとクライアント間で必然的に異なる場合(たとえば、タイムスタンプ)、ハイドレーションの不一致警告を抑制できます。
要素に関するハイドレーション警告を抑制するには、suppressHydrationWarning={true}
を追加します。
export default function App() { return ( <h1 suppressHydrationWarning={true}> Current Date: {new Date().toLocaleDateString()} </h1> ); }
これは1レベルの深さでのみ機能し、エスケープハッチとして意図されています。乱用しないでください。テキストコンテンツでない限り、Reactはそれを修正しようとしないため、今後の更新まで一貫性がなくなる可能性があります。
異なるクライアントとサーバーのコンテンツの処理
サーバーとクライアントで意図的に異なるものをレンダリングする必要がある場合は、2パスレンダリングを実行できます。クライアントで異なるものをレンダリングするコンポーネントは、state変数であるisClient
のようなものを読み取ることができます。これは、Effect で 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> ); }
このようにすると、初期レンダリングパスはサーバーと同じコンテンツをレンダリングし、不一致を回避しますが、ハイドレーションの直後に同期的に追加のパスが発生します。
ハイドレートされたルートコンポーネントの更新
ルートのハイドレーションが完了したら、root.render
を呼び出して、ルートのReactコンポーネントを更新できます。createRoot
の場合とは異なり、通常はこれを行う必要はありません。これは初期コンテンツがすでにHTMLとしてレンダリングされているためです。
ハイドレーション後にどこかの時点で root.render
を呼び出し、コンポーネントツリー構造が以前にレンダリングされたものと一致する場合、Reactは状態を保持します。 この例では、入力欄にタイプできます。これは、この例で毎秒繰り返される render
呼び出しによる更新が破壊的ではないことを意味します。
import { hydrateRoot } from 'react-dom/client'; import './styles.css'; import App from './App.js'; const root = hydrateRoot( document.getElementById('root'), <App counter={0} /> ); let i = 0; setInterval(() => { root.render(<App counter={i} />); i++; }, 1000);
ハイドレートされたルートで root.render
を呼び出すことはまれです。通常は、代わりにコンポーネントの1つの中で状態を更新します。
キャッチされないエラーのダイアログを表示する
デフォルトでは、Reactはキャッチされないすべてのエラーをコンソールに記録します。独自のエラーレポートを実装するには、オプションの onUncaughtError
ルートオプションを指定できます。
import { hydrateRoot } from 'react-dom/client';
const root = hydrateRoot(
document.getElementById('root'),
<App />,
{
onUncaughtError: (error, errorInfo) => {
console.error(
'Uncaught error',
error,
errorInfo.componentStack
);
}
}
);
root.render(<App />);
onUncaughtError オプションは、2つの引数で呼び出される関数です。
- スローされた エラー。
- errorInfo オブジェクト。エラーの componentStack が含まれています。
onUncaughtError
ルートオプションを使用して、エラーダイアログを表示できます。
import { hydrateRoot } from "react-dom/client"; import App from "./App.js"; import {reportUncaughtError} from "./reportError"; import "./styles.css"; import {renderToString} from 'react-dom/server'; const container = document.getElementById("root"); const root = hydrateRoot(container, <App />, { onUncaughtError: (error, errorInfo) => { if (error.message !== 'Known error') { reportUncaughtError({ error, componentStack: errorInfo.componentStack }); } } });
エラー境界のエラーの表示
デフォルトでは、Reactはエラー境界によって捕捉されたすべてのエラーをconsole.error
に出力します。この動作を上書きするには、エラー境界によって捕捉されたエラーに対するオプションのonCaughtError
ルートオプションを提供できます。
import { hydrateRoot } from 'react-dom/client';
const root = hydrateRoot(
document.getElementById('root'),
<App />,
{
onCaughtError: (error, errorInfo) => {
console.error(
'Caught error',
error,
errorInfo.componentStack
);
}
}
);
root.render(<App />);
onCaughtErrorオプションは、2つの引数で呼び出される関数です。
- 境界によって捕捉されたエラーです。
- errorInfo オブジェクト。エラーの componentStack が含まれています。
onCaughtError
ルートオプションを使用して、エラーダイアログを表示したり、既知のエラーをログからフィルタリングしたりできます。
import { hydrateRoot } from "react-dom/client"; import App from "./App.js"; import {reportCaughtError} from "./reportError"; import "./styles.css"; const container = document.getElementById("root"); const root = hydrateRoot(container, <App />, { onCaughtError: (error, errorInfo) => { if (error.message !== 'Known error') { reportCaughtError({ error, componentStack: errorInfo.componentStack }); } } });
回復可能なハイドレーションミスマッチエラーのダイアログを表示する
Reactがハイドレーションミスマッチを検出すると、クライアント上でレンダリングすることで自動的に回復を試みます。デフォルトでは、Reactはハイドレーションミスマッチエラーをconsole.error
に出力します。この動作を上書きするには、オプションのonRecoverableError
ルートオプションを提供できます。
import { hydrateRoot } from 'react-dom/client';
const root = hydrateRoot(
document.getElementById('root'),
<App />,
{
onRecoverableError: (error, errorInfo) => {
console.error(
'Caught error',
error,
error.cause,
errorInfo.componentStack
);
}
}
);
onRecoverableErrorオプションは、2つの引数で呼び出される関数です。
- Reactがスローするエラー。一部のエラーには、元の原因がerror.causeとして含まれている場合があります。
- エラーのcomponentStackを含むerrorInfoオブジェクト。
onRecoverableError
ルートオプションを使用して、ハイドレーションミスマッチのエラーダイアログを表示できます。
import { hydrateRoot } from "react-dom/client"; import App from "./App.js"; import {reportRecoverableError} from "./reportError"; import "./styles.css"; const container = document.getElementById("root"); const root = hydrateRoot(container, <App />, { onRecoverableError: (error, errorInfo) => { reportRecoverableError({ error, cause: error.cause, componentStack: errorInfo.componentStack }); } });
トラブルシューティング
「root.renderに2番目の引数を渡しました」というエラーが発生する
よくある間違いは、hydrateRoot
のオプションをroot.render(...)
に渡してしまうことです。
修正するには、ルートオプションをroot.render(...)
ではなく、hydrateRoot(...)
に渡してください。
// 🚩 Wrong: root.render only takes one argument.
root.render(App, {onUncaughtError});
// ✅ Correct: pass options to createRoot.
const root = hydrateRoot(container, <App />, {onUncaughtError});