createRoot 可讓您建立一個根目錄,以便在瀏覽器 DOM 節點內顯示 React 元件。

const root = createRoot(domNode, options?)

參考

createRoot(domNode, options?)

呼叫 createRoot 建立一個 React 根目錄,以在瀏覽器 DOM 元素內顯示內容。

import { createRoot } from 'react-dom/client';

const domNode = document.getElementById('root');
const root = createRoot(domNode);

React 將會為 domNode 建立一個根目錄,並接管其中 DOM 的管理。建立根目錄後,您需要呼叫 root.render 以在其中顯示 React 元件

root.render(<App />);

完全使用 React 建立的應用程式通常只會針對其根元件呼叫一次 createRoot。使用 React 建立頁面部分內容的頁面,可以根據需要使用多個不同的根目錄。

請參閱以下更多範例。

參數

  • domNode:一個 DOM 元素。React 將會為此 DOM 元素建立一個根目錄,並允許您在根目錄上呼叫函式,例如 render 來顯示渲染的 React 內容。

  • 選用 options:包含此 React 根目錄選項的物件。

    • 選用 onCaughtError:當 React 在錯誤邊界中攔截到錯誤時呼叫的回呼函式。使用錯誤邊界攔截到的 error 和包含 componentStackerrorInfo 物件呼叫。
    • 選用 onUncaughtError:當擲出錯誤且未被錯誤邊界攔截時呼叫的回呼函式。使用擲出的 error 和包含 componentStackerrorInfo 物件呼叫。
    • 選用 onRecoverableError:當 React 自動從錯誤中復原時呼叫的回呼函式。使用 React 擲出的 error 和包含 componentStackerrorInfo 物件呼叫。某些可復原的錯誤可能包含原始錯誤原因,作為 error.cause
    • 選用 identifierPrefix:React 用於由 useId 產生的 ID 的字串前綴。這在同個頁面使用多個根目錄時,有助於避免衝突。

回傳值

createRoot 會回傳一個物件,包含兩個方法:renderunmount

注意事項

  • 如果您的應用程式是伺服器端渲染的,則不支援使用 createRoot()。請改用 hydrateRoot()
  • 您的應用程式中可能只會呼叫一次 createRoot。如果您使用框架,它可能會幫您完成此呼叫。
  • 當您想要在 DOM 樹中不同於組件子項的部分渲染 JSX(例如,模態框或工具提示)時,請使用 createPortal,而不是 createRoot

root.render(reactNode)

呼叫 root.render 將一段 JSX(「React 節點」)顯示到 React 根目錄的瀏覽器 DOM 節點中。

root.render(<App />);

React 將在 root 中顯示 <App />,並接管其中 DOM 的管理。

請參閱以下更多範例。

參數

  • reactNode:您想要顯示的 *React 節點*。這通常是一段 JSX,例如 <App />,但您也可以傳遞使用 createElement() 建構的 React 元素、字串、數字、nullundefined

回傳值

root.render 回傳 undefined

注意事項

  • 第一次呼叫 root.render 時,React 會在將 React 組件渲染到 React 根目錄之前,清除其中所有現有的 HTML 內容。

  • 如果您的根目錄的 DOM 節點包含伺服器或建置期間由 React 產生的 HTML,請改用 hydrateRoot(),它會將事件處理程式附加到現有的 HTML。

  • 如果您在同一個根節點上多次呼叫 render,React 將會視需要更新 DOM 以反映您傳遞的最新 JSX。React 會藉由將其與先前渲染的樹狀結構「比對」來決定 DOM 的哪些部分可以重複使用,哪些需要重新建立。在同一個根節點上再次呼叫 render 類似於在根組件上呼叫 set 函式:React 會避免不必要的 DOM 更新。


root.unmount()

呼叫 root.unmount 可以銷毀 React 根節點內已渲染的樹狀結構。

root.unmount();

完全使用 React 建構的應用程式通常不會呼叫 root.unmount

當您的 React 根節點的 DOM 節點(或其任何祖先節點)可能被其他程式碼從 DOM 中移除時,這會很有用。例如,想像一個 jQuery 標籤面板,它會從 DOM 中移除非活動的標籤頁。如果一個標籤頁被移除,它裡面的所有內容(包括裡面的 React 根節點)也會從 DOM 中移除。在這種情況下,您需要透過呼叫 root.unmount 來告知 React「停止」管理已移除根節點的內容。否則,已移除根節點內的組件將不知道要清理並釋放全域資源,例如訂閱。

呼叫 root.unmount 將會卸載根節點中的所有組件,並將 React 與根 DOM 節點「分離」,包括移除樹狀結構中的任何事件處理程式或狀態。

參數

root.unmount 不接受任何參數。

回傳值 ...

root.unmount 回傳 undefined

注意事項 ...

  • 呼叫 root.unmount 將會卸載樹狀結構中的所有組件,並將 React 與根 DOM 節點「分離」。

  • 呼叫 root.unmount 後,您無法在同一個根節點上再次呼叫 root.render。嘗試在已卸載的根節點上呼叫 root.render 將會拋出「無法更新已卸載的根節點」錯誤。但是,您可以在前一個根節點已被卸載後,為同一個 DOM 節點建立新的根節點。


用法 ...

渲染完全使用 React 建構的應用程式 ...

如果您的應用程式完全使用 React 建構,請為整個應用程式建立單一根節點。

import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root'));
root.render(<App />);

通常,您只需要在啟動時執行一次此程式碼。它將會

  1. 找到您 HTML 中定義的 瀏覽器 DOM 節點
  2. 在其中顯示應用程式的 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 時,每個組件都可以透過使用狀態來完成。當您需要在 DOM 節點之外顯示額外內容(例如模態框或工具提示)時,請使用入口網站來渲染它

備註

如果你的 HTML 是空的,使用者在應用程式的 JavaScript 程式碼載入並執行之前會看到空白頁面。

<div id="root"></div>

這感覺起來會非常慢!為了改善這個問題,你可以從你的元件在伺服器上或建置過程中生成初始 HTML。這樣你的訪客就可以在任何 JavaScript 程式碼載入之前閱讀文字、查看圖片和點擊連結。我們建議使用框架來自動完成這項優化。根據執行的時間點,這稱為伺服器端渲染 (SSR)靜態網站生成 (SSG)。

陷阱

使用伺服器渲染或靜態生成的應用程式必須呼叫 hydrateRoot 而不是 createRootReact 將會注水(重複使用)你的 HTML 中的 DOM 節點,而不是銷毀並重新建立它們。


渲染部分使用 React 建置的頁面

如果你的頁面並非完全使用 React 建置,你可以多次呼叫 createRoot 來為每個由 React 管理的頂層 UI 建立一個根。你可以透過呼叫 root.render 在每個根中顯示不同的內容。

這裡,兩個不同的 React 元件被渲染到在 index.html 檔案中定義的兩個 DOM 節點中。

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 就會保留狀態。請注意你可以如何在輸入框中輸入文字,這表示在本例中,每秒重複呼叫 render 的更新並非破壞性的。

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 並不常見。通常,你的元件會更新狀態

顯示未攔截錯誤的對話框

預設情況下,React 會將所有未攔截的錯誤記錄到控制台。要實作你自己的錯誤報告,你可以提供選用的 onUncaughtError 根選項。

import { createRoot } from 'react-dom/client';

const root = createRoot(
document.getElementById('root'),
{
onUncaughtError: (error, errorInfo) => {
console.error(
'Uncaught error',
error,
errorInfo.componentStack
);
}
}
);
root.render(<App />);

onUncaughtError 選項是一個带有兩個參數的函式:

  1. 拋出的 error(錯誤)。
  2. 一個包含錯誤 errorInfo 物件,其中包含錯誤的 componentStack(元件堆疊)。

你可以使用 onUncaughtError 根選項來顯示錯誤對話框。

import { createRoot } from "react-dom/client";
import App from "./App.js";
import {reportUncaughtError} from "./reportError";
import "./styles.css";

const container = document.getElementById("root");
const root = createRoot(container, {
  onUncaughtError: (error, errorInfo) => {
    if (error.message !== 'Known error') {
      reportUncaughtError({
        error,
        componentStack: errorInfo.componentStack
      });
    }
  }
});
root.render(<App />);

顯示錯誤邊界錯誤

預設情況下,React 會將錯誤邊界攔截的所有錯誤記錄到 console.error。要覆蓋此行為,你可以提供選用的 onCaughtError 根選項來處理錯誤邊界攔截的錯誤。

import { createRoot } from 'react-dom/client';

const root = createRoot(
document.getElementById('root'),
{
onCaughtError: (error, errorInfo) => {
console.error(
'Caught error',
error,
errorInfo.componentStack
);
}
}
);
root.render(<App />);

onCaughtError 選項是一個带有兩個參數的函式:

  1. 邊界攔截的 error(錯誤)。
  2. 一個包含錯誤 errorInfo 物件,其中包含錯誤的 componentStack(元件堆疊)。

你可以使用 onCaughtError 根選項來顯示錯誤對話框或篩選記錄中已知的錯誤。

import { createRoot } from "react-dom/client";
import App from "./App.js";
import {reportCaughtError} from "./reportError";
import "./styles.css";

const container = document.getElementById("root");
const root = createRoot(container, {
  onCaughtError: (error, errorInfo) => {
    if (error.message !== 'Known error') {
      reportCaughtError({
        error, 
        componentStack: errorInfo.componentStack,
      });
    }
  }
});
root.render(<App />);

顯示可復原錯誤的對話框

React 可能會自動再次渲染元件,以嘗試從渲染中拋出的錯誤中復原。如果成功,React 會將可復原的錯誤記錄到控制台以通知開發人員。要覆蓋此行為,你可以提供選用的 onRecoverableError 根選項。

import { createRoot } from 'react-dom/client';

const root = createRoot(
document.getElementById('root'),
{
onRecoverableError: (error, errorInfo) => {
console.error(
'Recoverable error',
error,
error.cause,
errorInfo.componentStack,
);
}
}
);
root.render(<App />);

onRecoverableError 選項是一個带有兩個參數的函式:

  1. React 拋出的 error(錯誤)。某些錯誤可能包含原始原因,如 error.cause
  2. 一個包含錯誤 errorInfo 物件,其中包含錯誤的 componentStack(元件堆疊)。

你可以使用 onRecoverableError 根選項來顯示錯誤對話框。

import { createRoot } from "react-dom/client";
import App from "./App.js";
import {reportRecoverableError} from "./reportError";
import "./styles.css";

const container = document.getElementById("root");
const root = createRoot(container, {
  onRecoverableError: (error, errorInfo) => {
    reportRecoverableError({
      error,
      cause: error.cause,
      componentStack: errorInfo.componentStack,
    });
  }
});
root.render(<App />);


疑難排解

我已經建立了一個根節點,但沒有任何顯示

請確認您沒有忘記將您的應用程式實際渲染到根節點中

import { createRoot } from 'react-dom/client';
import App from './App.js';

const root = createRoot(document.getElementById('root'));
root.render(<App />);

在您執行該操作之前,不會顯示任何內容。


我收到一個錯誤:「您傳遞了第二個參數給 root.render」

一個常見的錯誤是將 createRoot 的選項傳遞給 root.render(...)

主控台
警告:您傳遞了第二個參數給 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 />);

我收到一個錯誤:「目標容器不是 DOM 元素」

這個錯誤表示您傳遞給 createRoot 的任何內容都不是 DOM 節點。

如果您不確定發生了什麼事,請嘗試記錄它

const domNode = document.getElementById('root');
console.log(domNode); // ???
const root = createRoot(domNode);
root.render(<App />);

例如,如果 domNodenull,則表示 getElementById 傳回了 null。如果在您呼叫時文件中沒有具有指定 ID 的節點,就會發生這種情況。可能原因有幾個

  1. 您要查找的 ID 可能與您在 HTML 檔案中使用的 ID 不同。檢查是否有錯字!
  2. 您的套件的 <script> 標籤無法「看到」HTML 中在其之後出現的任何 DOM 節點。

導致此錯誤的另一個常見原因是編寫 createRoot(<App />) 而不是 createRoot(domNode)


我收到一個錯誤:「函數不是有效的 React 子項。」

這個錯誤表示您傳遞給 root.render 的任何內容都不是 React 元件。

如果您使用 Component 而不是 <Component /> 呼叫 root.render,就可能會發生這種情況

// 🚩 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 節點。這可能會比較慢,會重設焦點和捲動位置,並且可能會遺失其他使用者輸入。

伺服器渲染的應用程式必須使用 hydrateRoot 而不是 createRoot

import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

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

請注意,它的 API 不同。特別是,通常不會再有 root.render 呼叫。