createRoot 允许你创建一个根以在浏览器 DOM 节点内显示 React 组件。

¥createRoot lets you create a root to display React components inside a browser DOM node.

const root = createRoot(domNode, options?)

参考

¥Reference

createRoot(domNode, options?)

调用 createRoot 创建一个 React 根,用于在浏览器 DOM 元素中显示内容。

¥Call createRoot to create a React root for displaying content inside a browser DOM element.

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

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

React 将为 domNode 创建一个根,并接管管理其中的 DOM。创建根后,你需要调用 root.render 以在其中显示一个 React 组件:

¥React will create a root for the domNode, and take over managing the DOM inside it. After you’ve created a root, you need to call root.render to display a React component inside of it:

root.render(<App />);

完全使用 React 构建的应用通常只有一个 createRoot 调用其根组件。将 React 的 “sprinkles” 用于页面的某些部分的页面可以根据需要具有尽可能多的单独根。

¥An app fully built with React will usually only have one createRoot call for its root component. A page that uses “sprinkles” of React for parts of the page may have as many separate roots as needed.

请参阅下面的更多示例。

¥See more examples below.

参数

¥Parameters

  • domNodeDOM 元素。 React 将为此 DOM 元素创建一个根,并允许你调用根上的函数,例如 render 以显示渲染的 React 内容。

    ¥domNode: A DOM element. React will create a root for this DOM element and allow you to call functions on the root, such as render to display rendered React content.

  • 可选 options:具有此 React 根选项的对象。

    ¥optional options: An object with options for this React root.

    • 可选 onCaughtError:当 React 在错误边界中捕获错误时调用的回调。使用被错误边界捕获的 error 和包含 componentStackerrorInfo 对象调用。

      ¥optional onCaughtError: Callback called when React catches an error in an Error Boundary. Called with the error caught by the Error Boundary, and an errorInfo object containing the componentStack.

    • 可选 onUncaughtError:当抛出错误但未被错误边界捕获时调用的回调。使用抛出的 error 和包含 componentStackerrorInfo 对象进行调用。

      ¥optional onUncaughtError: Callback called when an error is thrown and not caught by an Error Boundary. Called with the error that was thrown, and an errorInfo object containing the componentStack.

    • 可选 onRecoverableError:当 React 自动从错误中恢复时调用的回调。使用 React 抛出的 error 和包含 componentStackerrorInfo 对象调用。某些可恢复错误可能将原始错误原因包括为 error.cause

      ¥optional onRecoverableError: Callback called when React automatically recovers from errors. Called with an error React throws, and an errorInfo object containing the componentStack. Some recoverable errors may include the original error cause as error.cause.

    • 可选 identifierPrefix:React 用于 useId 生成的 ID 的字符串前缀 有助于避免在同一页面上使用多个根时发生冲突。

      ¥optional identifierPrefix: A string prefix React uses for IDs generated by useId. Useful to avoid conflicts when using multiple roots on the same page.

返回

¥Returns

createRoot 返回一个有两个方法的对象:renderunmount

¥createRoot returns an object with two methods: render and unmount.

注意事项

¥Caveats

  • 如果你的应用是服务器渲染的,则不支持使用 createRoot()。请改用 hydrateRoot()

    ¥If your app is server-rendered, using createRoot() is not supported. Use hydrateRoot() instead.

  • 你的应用中可能只有一个 createRoot 调用。如果你使用框架,它可能会为你执行此调用。

    ¥You’ll likely have only one createRoot call in your app. If you use a framework, it might do this call for you.

  • 当你想在 DOM 树的不同部分渲染一段 JSX 时,它不是你的组件的子级(例如,模态或工具提示),请使用 createPortal 而不是 createRoot

    ¥When you want to render a piece of JSX in a different part of the DOM tree that isn’t a child of your component (for example, a modal or a tooltip), use createPortal instead of createRoot.


root.render(reactNode)

调用 root.renderJSX (“React 节点”) 的一部分显示到 React root 的浏览器 DOM 节点中。

¥Call root.render to display a piece of JSX (“React node”) into the React root’s browser DOM node.

root.render(<App />);

React 将在 root 中显示 <App />,并接管管理其中的 DOM。

¥React will display <App /> in the root, and take over managing the DOM inside it.

请参阅下面的更多示例。

¥See more examples below.

参数

¥Parameters

  • reactNode:你要显示的 React 节点。这通常是一段 JSX,如 <App />,但你也可以传递一个由 createElement()、字符串、数字、nullundefined 构造的 React 元素。

    ¥reactNode: A React node that you want to display. This will usually be a piece of JSX like <App />, but you can also pass a React element constructed with createElement(), a string, a number, null, or undefined.

返回

¥Returns

root.render 返回 undefined

¥root.render returns undefined.

注意事项

¥Caveats

  • 第一次调用 root.render 时,React 将清除 React 根目录中所有现有的 HTML 内容,然后再将 React 组件渲染到其中。

    ¥The first time you call root.render, React will clear all the existing HTML content inside the React root before rendering the React component into it.

  • 如果你的根节点的 DOM 节点包含 React 在服务器上或构建期间生成的 HTML,请改用 hydrateRoot(),它将事件处理程序附加到现有 HTML。

    ¥If your root’s DOM node contains HTML generated by React on the server or during the build, use hydrateRoot() instead, which attaches the event handlers to the existing HTML.

  • 如果你在同一个根上多次调用 render,React 将根据需要更新 DOM 以反映你传递的最新 JSX。React 将决定 DOM 的哪些部分可以重用,哪些需要由 “匹配它” 使用之前渲染的树重新创建。再次在同一个根上调用 render 类似于在根组件上调用 set 函数:React 避免了不必要的 DOM 更新。

    ¥If you call render on the same root more than once, React will update the DOM as necessary to reflect the latest JSX you passed. React will decide which parts of the DOM can be reused and which need to be recreated by “matching it up” with the previously rendered tree. Calling render on the same root again is similar to calling the set function on the root component: React avoids unnecessary DOM updates.


root.unmount()

调用 root.unmount 以销毁 React 根内的渲染树。

¥Call root.unmount to destroy a rendered tree inside a React root.

root.unmount();

完全使用 React 构建的应用通常不会调用 root.unmount

¥An app fully built with React will usually not have any calls to root.unmount.

如果你的 React 根的 DOM 节点(或其任何祖级节点)可能被其他代码从 DOM 中删除,这将非常有用。例如,假设一个 jQuery 选项卡面板从 DOM 中删除非活动选项卡。如果一个选项卡被删除,其中的所有内容(包括里面的 React 根)也会从 DOM 中删除。在这种情况下,你需要通过调用 root.unmount 告诉 React “stop” 管理删除的根目录的内容。否则,被删除的根内的组件将不知道清理和释放订阅等全局资源。

¥This is mostly useful if your React root’s DOM node (or any of its ancestors) may get removed from the DOM by some other code. For example, imagine a jQuery tab panel that removes inactive tabs from the DOM. If a tab gets removed, everything inside it (including the React roots inside) would get removed from the DOM as well. In that case, you need to tell React to “stop” managing the removed root’s content by calling root.unmount. Otherwise, the components inside the removed root won’t know to clean up and free up global resources like subscriptions.

调用 root.unmount 将从根 DOM 节点卸载根中的所有组件和 “detach” React,包括删除树中的任何事件处理程序或状态。

¥Calling root.unmount will unmount all the components in the root and “detach” React from the root DOM node, including removing any event handlers or state in the tree.

参数

¥Parameters

root.unmount 没有参数。

¥root.unmount does not accept any parameters.

返回

¥Returns

root.unmount 返回 undefined

¥root.unmount returns undefined.

注意事项

¥Caveats

  • 调用 root.unmount 将从根 DOM 节点卸载树中的所有组件和 “detach” React。

    ¥Calling root.unmount will unmount all the components in the tree and “detach” React from the root DOM node.

  • 一旦你调用 root.unmount,你就不能在同一个根上再次调用 root.render。尝试在未挂载的根上调用 root.render 将引发 “无法更新卸载的根目录” 错误。但是,你可以在卸载该节点的先前根之后为同一 DOM 节点创建一个新根。

    ¥Once you call root.unmount you cannot call root.render again on the same root. Attempting to call root.render on an unmounted root will throw a “Cannot update an unmounted root” error. However, you can create a new root for the same DOM node after the previous root for that node has been unmounted.


用法

¥Usage

渲染完全用 React 构建的应用

¥Rendering an app fully built with React

如果你的应用完全使用 React 构建,请为你的整个应用创建一个根目录。

¥If your app is fully built with React, create a single root for your entire app.

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

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

通常,你只需要在启动时运行此代码一次。它会:

¥Usually, you only need to run this code once at startup. It will:

  1. 找到在你的 HTML 中定义的 浏览器 DOM 节点

    ¥Find the browser DOM node defined in your HTML.

  2. 在内部显示你的应用的 React 组件

    ¥Display the React component for your app inside.

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

¥If your app is fully built with React, you shouldn’t need to create any more roots, or to call root.render again.

从这一点开始,React 将管理整个应用的 DOM。要添加更多组件,将它们嵌套在 App 组件中。 当你需要更新 UI 时,你的每个组件都可以通过 使用状态。 执行此操作 当你需要在 DOM 节点外部显示额外内容(如模式或工具提示)时,用门户渲染它。

¥From this point on, React will manage the DOM of your entire app. To add more components, nest them inside the App component. When you need to update the UI, each of your components can do this by using state. When you need to display extra content like a modal or a tooltip outside the DOM node, render it with a portal.

注意

当你的 HTML 为空时,用户会看到一个空白页面,直到应用的 JavaScript 代码加载并运行:

¥When your HTML is empty, the user sees a blank page until the app’s JavaScript code loads and runs:

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

这会感觉很慢!要解决这个问题,你可以从你的组件生成初始 HTML 在服务器上或构建期间。 然后你的访问者可以在加载任何 JavaScript 代码之前阅读文本、查看图片和单击链接。我们推荐 使用框架,它可以开箱即用地进行这种优化。根据它运行的时间,这称为服务器端渲染 (SSR) 或静态站点生成 (SSG)。

¥This can feel very slow! To solve this, you can generate the initial HTML from your components on the server or during the build. Then your visitors can read text, see images, and click links before any of the JavaScript code loads. We recommend using a framework that does this optimization out of the box. Depending on when it runs, this is called server-side rendering (SSR) or static site generation (SSG).

易犯错误

使用服务器渲染或静态生成的应用必须调用 hydrateRoot 而不是 createRoot。然后,React 将从你的 HTML 中混合(重用)DOM 节点,而不是销毁和重新创建它们。

¥Apps using server rendering or static generation must call hydrateRoot instead of createRoot. React will then hydrate (reuse) the DOM nodes from your HTML instead of destroying and re-creating them.


渲染部分使用 React 构建的页面

¥Rendering a page partially built with React

如果你的页面 不是完全用 React 构建的,你可以多次调用 createRoot 来为 React 管理的每个顶层 UI 片段创建一个根。可以通过调用 root.render. 在每个根中显示不同的内容

¥If your page isn’t fully built with React, you can call createRoot multiple times to create a root for each top-level piece of UI managed by React. You can display different content in each root by calling root.render.

在这里,两个不同的 React 组件被渲染到 index.html 文件中定义的两个 DOM 节点中:

¥Here, two different React components are rendered into two DOM nodes defined in the index.html file:

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 节点,然后手动将其添加到文档中。

¥You could also create a new DOM node with document.createElement() and add it to the document manually.

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.

¥To remove the React tree from the DOM node and clean up all the resources used by it, call root.unmount.

root.unmount();

如果你的 React 组件位于用不同框架编写的应用中,这将非常有用。

¥This is mostly useful if your React components are inside an app written in a different framework.


更新根组件

¥Updating a root component

你可以在同一个根上多次调用 render。只要组件树结构与之前渲染的内容相匹配,React 就会 保持状态。 通知你如何键入输入,这意味着在这个例子中每秒重复 render 调用的更新不是破坏性的:

¥You can call render more than once on the same root. As long as the component tree structure matches up with what was previously rendered, React will preserve the state. Notice how you can type in the input, which means that the updates from repeated render calls every second in this example are not destructive:

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 并不常见。通常,你的组件将改为 更新状态

¥It is uncommon to call render multiple times. Usually, your components will update state instead.

显示未捕获错误的对话框

¥Show a dialog for uncaught errors

默认情况下,React 会将所有未捕获的错误记录到控制台。要实现你自己的错误报告,你可以提供可选的 onUncaughtError 根选项:

¥By default, React will log all uncaught errors to the console. To implement your own error reporting, you can provide the optional onUncaughtError root option:

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 选项是一个使用两个参数调用的函数:

¥The onUncaughtError option is a function called with two arguments:

  1. 抛出的 error

    ¥The error that was thrown.

  2. 包含错误的 componentStackerrorInfo 对象。

    ¥An errorInfo object that contains the componentStack of the error.

你可以使用 onUncaughtError 根选项显示错误对话框:

¥You can use the onUncaughtError root option to display error dialogs:

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 />);

显示错误边界错误

¥Displaying Error Boundary errors

默认情况下,React 会将错误边界捕获的所有错误记录到 console.error。要覆盖此行为,你可以提供可选的 onCaughtError 根选项来处理 错误边界 捕获的错误:

¥By default, React will log all errors caught by an Error Boundary to console.error. To override this behavior, you can provide the optional onCaughtError root option to handle errors caught by an Error Boundary:

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 选项是一个使用两个参数调用的函数:

¥The onCaughtError option is a function called with two arguments:

  1. 被边界捕获的 error

    ¥The error that was caught by the boundary.

  2. 包含错误的 componentStackerrorInfo 对象。

    ¥An errorInfo object that contains the componentStack of the error.

你可以使用 onCaughtError 根选项显示错误对话框或从日志中过滤已知错误:

¥You can use the onCaughtError root option to display error dialogs or filter known errors from logging:

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 />);

显示可恢复错误的对话框

¥Displaying a dialog for recoverable errors

React 可能会自动第二次渲染组件,以尝试从渲染中抛出的错误中恢复。如果成功,React 会将可恢复错误记录到控制台以通知开发者。要覆盖此行为,你可以提供可选的 onRecoverableError 根选项:

¥React may automatically render a component a second time to attempt to recover from an error thrown in render. If successful, React will log a recoverable error to the console to notify the developer. To override this behavior, you can provide the optional onRecoverableError root option:

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 选项是一个使用两个参数调用的函数:

¥The onRecoverableError option is a function called with two arguments:

  1. React 抛出的 error。某些错误可能将原始原因包括为 error.cause

    ¥The error that React throws. Some errors may include the original cause as error.cause.

  2. 包含错误的 componentStackerrorInfo 对象。

    ¥An errorInfo object that contains the componentStack of the error.

你可以使用 onRecoverableError 根选项显示错误对话框:

¥You can use the onRecoverableError root option to display error dialogs:

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 />);


故障排除

¥Troubleshooting

我已经创建了一个根,但没有显示任何内容

¥I’ve created a root, but nothing is displayed

确保你没有忘记实际将你的应用渲染到根目录中:

¥Make sure you haven’t forgotten to actually render your app into the root:

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

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

在你这样做之前,不会显示任何内容。

¥Until you do that, nothing is displayed.


我收到错误:“你向 root.render 传递了第二个参数”

¥I’m getting an error: “You passed a second argument to root.render”

一个常见的错误是将 createRoot 的选项传递给 root.render(...)

¥A common mistake is to pass the options for createRoot to root.render(...):

Console

要修复此问题,请将根选项传递给 createRoot(...),而不是 root.render(...)

¥To fix, pass the root options to createRoot(...), not 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 元素”

¥I’m getting an error: “Target container is not a DOM element”

此错误意味着你传递给 createRoot 的任何内容都不是 DOM 节点。

¥This error means that whatever you’re passing to createRoot is not a DOM node.

如果你不确定发生了什么,请尝试记录它:

¥If you’re not sure what’s happening, try logging it:

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

例如,如果 domNodenull,则表示 getElementById 返回了 null。如果在你调用时文档中没有具有给定 ID 的节点,则会发生这种情况。可能有以下几个原因:

¥For example, if domNode is null, it means that getElementById returned null. This will happen if there is no node in the document with the given ID at the time of your call. There may be a few reasons for it:

  1. 你要查找的 ID 可能与你在 HTML 文件中使用的 ID 不同。检查错别字!

    ¥The ID you’re looking for might differ from the ID you used in the HTML file. Check for typos!

  2. 你的 bundle 的 <script> 标签不能 “看到” 在 HTML 中出现在它之后的任何 DOM 节点。

    ¥Your bundle’s <script> tag cannot “see” any DOM nodes that appear after it in the HTML.

获得此错误的另一种常见方法是写 createRoot(<App />) 而不是 createRoot(domNode)

¥Another common way to get this error is to write createRoot(<App />) instead of createRoot(domNode).


我收到错误:“函数作为 React 子项无效。”

¥I’m getting an error: “Functions are not valid as a React child.”

这个错误意味着你传递给 root.render 的任何东西都不是 React 组件。

¥This error means that whatever you’re passing to root.render is not a React component.

如果你使用 Component 而不是 <Component /> 调用 root.render,则可能会发生这种情况:

¥This may happen if you call root.render with Component instead of <Component />:

// 🚩 Wrong: App is a function, not a Component.
root.render(App);

// ✅ Correct: <App /> is a component.
root.render(<App />);

或者,如果你将一个函数传递给 root.render,而不是调用它的结果:

¥Or if you pass a function to root.render, instead of the result of calling it:

// 🚩 Wrong: createApp is a function, not a component.
root.render(createApp);

// ✅ Correct: call createApp to return a component.
root.render(createApp());

我的服务器渲染的 HTML 从头开始重新创建

¥My server-rendered HTML gets re-created from scratch

如果你的应用是服务器渲染的并且包含由 React 生成的初始 HTML,你可能会注意到创建根并调用 root.render 会删除所有 HTML,然后从头开始重新创建所有 DOM 节点。这可能会更慢,重置焦点和滚动位置,并且可能会丢失其他用户输入。

¥If your app is server-rendered and includes the initial HTML generated by React, you might notice that creating a root and calling root.render deletes all that HTML, and then re-creates all the DOM nodes from scratch. This can be slower, resets focus and scroll positions, and may lose other user input.

服务器渲染的应用必须使用 hydrateRoot 而不是 createRoot

¥Server-rendered apps must use hydrateRoot instead of createRoot:

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

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

请注意,它的 API 是不同的。特别是,通常不会再有 root.render 调用。

¥Note that its API is different. In particular, usually there will be no further root.render call.


React 中文网 - 粤ICP备13048890号