createRoot
createRoot
は、ブラウザの DOM ノード内に React コンポーネントを表示するためのルートを作成します。
const root = createRoot(domNode, options?)
リファレンス
createRoot(domNode, options?)
createRoot
を呼び出して、ブラウザの DOM 要素内にコンテンツを表示するための React ルートを作成します。
import { createRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = createRoot(domNode);
React は domNode
に対応するルートを作成し、その内部の DOM を管理します。ルートを作成した後、その内部に React コンポーネントを表示するために root.render
を呼び出す必要があります。
root.render(<App />);
React で完全に構築されたアプリには、ルートコンポーネントのための createRoot
呼び出しが通常 1 つのみ存在します。ページ内に React を「散りばめて」使用するページの場合は、必要なだけ複数のルートを持つことができます。
引数
-
domNode
: DOM 要素。React はこの DOM 要素に対応するルートを作成し、レンダーされた React コンテンツを表示するためのrender
など、関数をルート上で呼び出せるようにします。 -
省略可能
options
: この React ルートに関するオプションが含まれたオブジェクト。- 省略可能
onCaughtError
: エラーバウンダリ内で React がエラーをキャッチしたときに呼び出されるコールバック。エラーバウンダリにキャッチされたerror
と、componentStack
を含んだerrorInfo
を引数にして呼び出されます。 - 省略可能
onUncaughtError
: エラーがスローされたがエラーバウンダリでキャッチされなかったときに呼び出されるコールバック。スローされたerror
と、componentStack
を含んだerrorInfo
を引数にして呼び出されます。 - 省略可能
onRecoverableError
: React が自動的にエラーから回復したときに呼び出されるコールバック。React がスローするerror
と、componentStack
を含んだerrorInfo
を引数にして呼び出されます。復帰可能なエラーの一部は元のエラーをerror.cause
として含んでいます。 - 省略可能
identifierPrefix
: React がuseId
によって生成する ID に使用する文字列プレフィックス。同じページ上に複数のルートを使用する際に、競合を避けるために用います。
- 省略可能
返り値
createRoot
は、render
と unmount
の 2 つのメソッドを持つオブジェクトを返します。
注意点
- アプリがサーバレンダリングを使用している場合、
createRoot()
の使用はサポートされていません。代わりにhydrateRoot()
を使用してください。 - アプリ内で
createRoot
を呼び出すのは通常 1 回だけです。フレームワークを使用している場合、この呼び出しはフレームワークが代わりに行う可能性があります。 - DOM ツリー内の、コンポーネントの子ではない別の部分に JSX をレンダーしたい場合(例えばモーダルやツールチップ)、
createRoot
の代わりにcreatePortal
を使用してください。
root.render(reactNode)
root.render
を呼び出して、React ルートのブラウザ DOM ノードに JSX(“React ノード”)を表示します。
root.render(<App />);
React は root
に <App />
を表示し、その内部の DOM の管理を行います。
引数
reactNode
: 表示したい React ノード。通常は<App />
のような JSX ですが、createElement()
で構築した React 要素や、文字列、数値、null
、またはundefined
を渡すこともできます。
返り値
root.render
は undefined
を返します。
注意点
-
root.render
を初めて呼び出したとき、React は React ルート内の既存の HTML コンテンツをすべてクリアしてから、React コンポーネントをレンダーします。 -
ルートの DOM ノードがサーバやビルド中に React によって生成された HTML を含んでいる場合は、既存の HTML にイベントハンドラをアタッチできる
hydrateRoot()
を使用してください。 -
同じルートに対して
render
を複数回呼び出すと、React は最新の JSX を反映するために必要なだけの DOM の更新を行います。React は、渡された JSX を以前にレンダーしたツリーと「マッチング」して、DOM のどの部分が再利用でき、どの部分を再作成する必要があるのかを決定します。同じルートに対して複数回render
を呼び出すことは、ルートコンポーネントでset
関数を呼び出すことに似ており、React は不必要な DOM 更新を回避します。 -
Although rendering is synchronous once it starts,
root.render(...)
is not. This means code afterroot.render()
may run before any effects (useLayoutEffect
,useEffect
) of that specific render are fired. This is usually fine and rarely needs adjustment. In rare cases where effect timing matters, you can wraproot.render(...)
influshSync
to ensure the initial render runs fully synchronously.const root = createRoot(document.getElementById('root'));root.render(<App />);// 🚩 The HTML will not include the rendered <App /> yet:console.log(document.body.innerHTML);
root.unmount()
root.unmount
を呼び出して、React ルート内にレンダーされたツリーを破棄します。
root.unmount();
React で完全に構築されたアプリには、通常、root.unmount
の呼び出しは一切ありません。
これは主に、React ルートの DOM ノード(またはその祖先のいずれか)が他のコードによって DOM から削除される可能性がある場合に有用です。例えば、非アクティブなタブを DOM から削除する jQuery のタブパネルがあると想像してみてください。タブが削除されると、(React ルートを含んだ)内部のすべてが DOM から削除されます。その場合、削除されたルートのコンテンツの管理を「停止」するよう React に伝えるために root.unmount
を呼び出す必要があります。そうしないと、削除されたルート内のコンポーネントは、データ購読などのグローバルリソースをクリーンアップして解放する必要があるということが分からないままになります。
root.unmount
を呼び出すことで、ルート内のすべてのコンポーネントがアンマウントされ、React がルート DOM ノードから「切り離され」ます。これには、ツリー内のイベントハンドラや state の削除も含まれます。
引数
root.unmount
は引数を受け付けません。
返り値
root.unmount
は undefined
を返します。
注意点
-
root.unmount
を呼び出すと、ツリー内のすべてのコンポーネントがアンマウントされ、React がルート DOM ノードから「切り離され」ます。 -
root.unmount
を呼び出した後、同一ルートで再度root.render
を呼び出すことはできません。アンマウント済みのルートでroot.render
を呼び出そうとすると、“Cannot update an unmounted root” というエラーがスローされます。ただし、ある DOM ノードに対する以前のルートがアンマウントされた後で、同じ DOM ノードに対して新しいルートを作成することは可能です。
使用法
React で完全に構築されたアプリのレンダー
アプリが完全に React で構築されている場合は、アプリ全体のための単一のルートを作成します。
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
通常、このコードは起動時に一度だけ実行する必要があります。このコードは以下のことを行います。
- HTML で定義されているブラウザの DOM ノードを見つけます。
- アプリの React コンポーネントをその内部に表示します。
import { createRoot } from 'react-dom/client'; import App from './App.js'; import './styles.css'; const root = createRoot(document.getElementById('root')); root.render(<App />);
アプリが完全に React で構築されている場合、さらにルートを作成したり、root.render
を再度呼び出したりする必要はありません。
この時点から、React がアプリ全体の DOM を管理します。さらにコンポーネントを追加するには、App
コンポーネントの中にネストします。UI を更新する必要がある場合、各コンポーネントが state を使用して行います。モーダルやツールチップなどの追加コンテンツをこの DOM ノードの外部に表示する必要がある場合、ポータルを使ってレンダーします。
React で部分的に構築されたページのレンダー
ページが完全には React で構築されていない場合、createRoot
を複数回呼び出して、React に管理させたいトップレベルの各 UI パーツに対してルートを作成することができます。各ルートで root.render
を呼び出して、それぞれに異なるコンテンツを表示することができます。
以下では、index.html
ファイルに定義されている 2 つの異なる DOM ノードに 2 つの異なる React コンポーネントがレンダーされています。
import './styles.css'; import { createRoot } from 'react-dom/client'; import { Comments, Navigation } from './Components.js'; const navDomNode = document.getElementById('navigation'); const navRoot = createRoot(navDomNode); navRoot.render(<Navigation />); const commentDomNode = document.getElementById('comments'); const commentRoot = createRoot(commentDomNode); commentRoot.render(<Comments />);
また、document.createElement()
を使用して新しい DOM ノードを作成し、それを手動でドキュメントに追加することもできます。
const domNode = document.createElement('div');
const root = createRoot(domNode);
root.render(<Comment />);
document.body.appendChild(domNode); // You can add it anywhere in the document
DOM ノードから React ツリーを削除し、それによって使用されたすべてのリソースをクリーンアップするには、root.unmount
を呼び出します。
root.unmount();
これは主に、React コンポーネントが別のフレームワークで書かれたアプリの中にある場合に役立ちます。
ルートコンポーネントの更新
同じルートに対して render
を複数回呼び出すことができます。コンポーネントツリーの構造が以前にレンダーされたものと一致していれば、React は state を保持します。以下の例で入力フィールドにタイプできることに着目してください。つまり毎秒 render
が繰り返し呼び出されていますが、更新により DOM が破壊されていないということです。
import { createRoot } from 'react-dom/client'; import './styles.css'; import App from './App.js'; const root = createRoot(document.getElementById('root')); let i = 0; setInterval(() => { root.render(<App counter={i} />); i++; }, 1000);
render
を複数回呼び出すことは滅多にありません。通常、コンポーネントは代わりに state の更新を行います。
本番環境でのエラーのロギング
デフォルトでは、React はすべてのエラーをコンソールに記録します。独自のエラーレポートの仕組みを実装するには、省略可能なルートオプションとして onUncaughtError
、onCaughtError
、onRecoverableError
のエラーハンドラを提供することができます。
import { createRoot } from "react-dom/client";
import { reportCaughtError } from "./reportError";
const container = document.getElementById("root");
const root = createRoot(container, {
onCaughtError: (error, errorInfo) => {
if (error.message !== "Known error") {
reportCaughtError({
error,
componentStack: errorInfo.componentStack,
});
}
},
});
onCaughtError は以下の 2 つの引数で呼びされる関数です。
- スローされた error。
- errorInfo オブジェクト。エラーの componentStack を含んでいる。
onUncaughtError
と onRecoverableError
を組み合わせて、独自のエラーレポーティングのシステムを実装できます。
import { createRoot } from "react-dom/client"; import App from "./App.js"; import { onCaughtErrorProd, onRecoverableErrorProd, onUncaughtErrorProd, } from "./reportError"; const container = document.getElementById("root"); const root = createRoot(container, { // Keep in mind to remove these options in development to leverage // React's default handlers or implement your own overlay for development. // The handlers are only specfied unconditionally here for demonstration purposes. onCaughtError: onCaughtErrorProd, onRecoverableError: onRecoverableErrorProd, onUncaughtError: onUncaughtErrorProd, }); root.render(<App />);
トラブルシューティング
ルートを作成したが何も表示されない
アプリを実際にルートにレンダーするのを忘れていないか確認してください。
import { createRoot } from 'react-dom/client';
import App from './App.js';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
これを行うまでは何も表示されません。
“You passed a second argument to root.render” というエラーが出る
よくある間違いとして、createRoot
用のオプションを root.render(...)
に渡してしまうことが挙げられます。
修正するには、ルートオプションを createRoot(...)
に渡すようにしてください。root.render(...)
ではありません。
// 🚩 Wrong: root.render only takes one argument.
root.render(App, {onUncaughtError});
// ✅ Correct: pass options to createRoot.
const root = createRoot(container, {onUncaughtError});
root.render(<App />);
“Target container is not a DOM element” というエラーが出る
このエラーは、createRoot
に渡しているものが DOM ノードでないことを意味します。
何が起こっているのかわからない場合は、ログを出力してみてください。
const domNode = document.getElementById('root');
console.log(domNode); // ???
const root = createRoot(domNode);
root.render(<App />);
例えば、domNode
が null
の場合、getElementById
が null
を返したことを意味します。これは、呼び出し時点でドキュメント内に指定した ID のノードが存在しない場合に発生します。こうなる理由はいくつか考えられます。
- 探している ID が HTML ファイルで使用した ID と異なっている。タイプミスをチェックしてください!
- DOM ノードがバンドルの
<script>
タグより後ろにあるため、スクリプトから「見え」ない。
このエラーが発生するもうひとつの一般的な理由は、createRoot(domNode)
ではなく createRoot(<App />)
と書いてしまっていることです。
“Functions are not valid as a React child.” というエラーが出る
このエラーは、root.render
に渡しているものが React コンポーネントでないことを意味します。
これは、root.render
を <Component />
ではなく Component
のように呼び出した場合に発生することがあります。
// 🚩 Wrong: App is a function, not a Component.
root.render(App);
// ✅ Correct: <App /> is a component.
root.render(<App />);
または、root.render
に関数を呼び出した結果ではなく関数自体を渡してしまった場合にも発生します。
// 🚩 Wrong: createApp is a function, not a component.
root.render(createApp);
// ✅ Correct: call createApp to return a component.
root.render(createApp());
サーバレンダリングされた HTML が再作成される
アプリがサーバでレンダーする形式であり、React によって生成された初期 HTML がある場合、ルートを作成して root.render
を呼び出すと、その HTML がすべて削除されて DOM ノードがゼロから再作成されることに気付かれるかもしれません。これにより処理が遅くなり、フォーカスやスクロール位置がリセットされ、ユーザ入力が失われる可能性があります。
サーバでレンダーされたアプリは、createRoot
の代わりに hydrateRoot
を使用する必要があります。
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(
document.getElementById('root'),
<App />
);
API が異なることに注意してください。特に、通常はこの後さらに root.render
を呼び出すことはありません。