Перейти к содержанию

createRoot

createRoot позволяет создать корень для отображения компонентов React внутри узла DOM браузера.

1
const root = createRoot(domNode, options?)

Описание

createRoot(domNode, options?)

Вызовите createRoot для создания корня React для отображения содержимого внутри элемента DOM браузера.

1
2
3
4
import { createRoot } from 'react-dom/client';

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

React создаст корень для domNode и возьмет на себя управление DOM внутри него. После создания корня необходимо вызвать root.render, чтобы отобразить внутри него компонент React:

1
root.render(<App />);

Приложение, полностью построенное на React, обычно имеет только один вызов createRoot для своего корневого компонента. Страница, которая использует "брызги" React для частей страницы, может иметь столько отдельных корней, сколько необходимо.

Параметры

  • domNode: DOM-элемент. React создаст корень для этого DOM-элемента и позволит вам вызывать функции на корне, такие как render для отображения отрисованного содержимого React.
  • опционально options: Объект с опциями для этого корня React.
    • optional onRecoverableError: Обратный вызов, вызываемый, когда React автоматически восстанавливает ошибки.
    • optional identifierPrefix: Строковый префикс, который React использует для идентификаторов, генерируемых useId. Полезно для предотвращения конфликтов при использовании нескольких корней на одной странице.

Возвращает

createRoot возвращает объект с двумя методами: render и unmount.

Ограничения

  • Если ваше приложение рендерится на сервере, использование createRoot() не поддерживается. Вместо этого используйте hydrateRoot().
  • Скорее всего, в вашем приложении будет только один вызов createRoot. Если вы используете фреймворк, он может выполнить этот вызов за вас.
  • Когда вы хотите отобразить JSX в другой части дерева DOM, которая не является дочерней для вашего компонента (например, модальный экран или всплывающая подсказка), используйте createPortal вместо createRoot.

root.render(reactNode)

Вызовите root.render для отображения части JSX ("React node") в DOM-узел браузера React root.

1
root.render(<App />);

React отобразит <App /> в root и возьмет на себя управление DOM внутри него.

Параметры

  • reactNode: React-узел, который вы хотите отобразить. Обычно это кусок JSX типа <App />, но вы также можете передать элемент React, созданный с помощью createElement(), строку, число, null или undefined.

Возвраты

root.render возвращает undefined.

Предупреждения

  • При первом вызове root.render, React очистит все существующее HTML-содержимое внутри корня React перед рендерингом в него компонента React.
  • Если узел DOM вашего корня содержит HTML, сгенерированный React на сервере или во время сборки, используйте вместо этого hydrateRoot(), который прикрепляет обработчики событий к существующему HTML.
  • Если вы вызываете render на одном и том же корне более одного раза, React будет обновлять DOM по мере необходимости, чтобы отразить последний JSX, который вы передали. React будет решать, какие части DOM могут быть использованы повторно, а какие должны быть созданы заново, "сопоставляя их" с ранее отрисованным деревом. Повторный вызов render на том же корне аналогичен вызову функции set на корневом компоненте: React позволяет избежать ненужных обновлений DOM.

root.unmount()

Вызовите root.unmount, чтобы уничтожить дерево рендеринга внутри корня React.

1
root.unmount();

Приложение, полностью построенное на React, обычно не содержит вызовов root.unmount.

Это в основном полезно, если DOM-узел вашего React root (или любой из его предков) может быть удален из DOM каким-либо другим кодом. Например, представьте себе панель вкладок jQuery, которая удаляет неактивные вкладки из DOM. Если вкладка будет удалена, все внутри нее (включая React roots внутри) также будет удалено из DOM. В этом случае вам нужно сказать React "прекратить" управление содержимым удаленного корня, вызвав root.unmount. В противном случае компоненты внутри удаленного корня не будут знать, что нужно очистить и освободить глобальные ресурсы, такие как подписки.

Вызов root.unmount размонтирует все компоненты в корне и "отсоединит" React от корневого DOM-узла, включая удаление любых обработчиков событий или состояния в дереве.

Параметры

root.unmount не принимает никаких параметров.

Возвраты

root.unmount возвращает не определено.

Ограничения

  • Вызов root.unmount приведет к размонтированию всех компонентов в дереве и "отсоединению" React от корневого DOM-узла.
  • После вызова root.unmount вы не сможете снова вызвать root.render на том же корне. Попытка вызвать root.render на немонтированном корне приведет к ошибке "Cannot update an unmounted root". Однако вы можете создать новый корень для одного и того же узла DOM после того, как предыдущий корень для этого узла был размонтирован.

Использование

Рендеринг приложения, полностью построенного на React

Если ваше приложение полностью построено с помощью React, создайте единый корень для всего приложения.

1
2
3
4
import { createRoot } from 'react-dom/client';

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

Обычно этот код нужно запускать только один раз при запуске. Он выполнит:

  1. Найдет узел DOM браузера, определенный в вашем HTML.
  2. Отобразит компонент React для вашего приложения внутри.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!DOCTYPE html>
<html>
    <head>
        <title>My app</title>
    </head>
    <body>
        <!-- This is the DOM node -->
        <div id="root"></div>
    </body>
</html>
1
2
3
4
5
6
import { createRoot } from 'react-dom/client';
import App from './App.js';
import './styles.css';

const root = createRoot(document.getElementById('root'));
root.render(<App />);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import { useState } from 'react';

export default function App() {
    return (
        <>
            <h1>Hello, world!</h1>
            <Counter />
        </>
    );
}

function Counter() {
    const [count, setCount] = useState(0);
    return (
        <button onClick={() => setCount(count + 1)}>
            You clicked me {count} times
        </button>
    );
}

Если ваше приложение полностью построено на React, вам не нужно больше создавать корни или снова вызывать root.render

С этого момента React будет управлять DOM всего вашего приложения. Чтобы добавить больше компонентов, вложите их внутрь компонента App Когда вам нужно обновить пользовательский интерфейс, каждый из ваших компонентов может сделать это, используя состояние Когда вам нужно отобразить дополнительный контент, например, модальное окно или подсказку, вне узла DOM, отобразите его с помощью портала.

Когда ваш HTML пуст, пользователь видит пустую страницу, пока не загрузится и не запустится код JavaScript приложения:

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

Это может показаться очень медленным! Чтобы решить эту проблему, вы можете генерировать исходный HTML из ваших компонентов на сервере или во время сборки. Тогда ваши посетители смогут читать текст, видеть изображения и нажимать на ссылки до того, как загрузится код JavaScript. Мы рекомендуем использовать фреймворк, который выполняет эту оптимизацию из коробки. В зависимости от того, когда она выполняется, это называется рендеринг на стороне сервера (SSR) или статическая генерация сайта (SSG).

Серверный рендеринг

Приложения, использующие серверный рендеринг или статическую генерацию, должны вызывать hydrateRoot вместо createRoot. React будет гидрировать (повторно использовать) узлы DOM из вашего HTML вместо их уничтожения и повторного создания.

Рендеринг страницы, частично построенной на React

Если ваша страница не полностью построена на React, вы можете вызвать createRoot несколько раз, чтобы создать корень для каждой части пользовательского интерфейса верхнего уровня, управляемой React. Вы можете отображать различное содержимое в каждом корне, вызывая root.render.

Здесь два разных компонента React отображаются в двух узлах DOM, определенных в файле index.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
    <head>
        <title>My app</title>
    </head>
    <body>
        <nav id="navigation"></nav>
        <main>
            <p>
                This paragraph is not rendered by React
                (open index.html to verify).
            </p>
            <section id="comments"></section>
        </main>
    </body>
</html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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 />);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
export function Navigation() {
    return (
        <ul>
            <NavLink href="/">Home</NavLink>
            <NavLink href="/about">About</NavLink>
        </ul>
    );
}

function NavLink({ href, children }) {
    return (
        <li>
            <a href={href}>{children}</a>
        </li>
    );
}

export function Comments() {
    return (
        <>
            <h2>Comments</h2>
            <Comment text="Hello!" author="Sophie" />
            <Comment text="How are you?" author="Sunil" />
        </>
    );
}

function Comment({ text, author }) {
    return (
        <p>
            {text}  <i>{author}</i>
        </p>
    );
}

Вы также можете создать новый узел DOM с помощью document.createElement() и добавить его в документ вручную.

1
2
3
4
5
const domNode = document.createElement('div');
const root = createRoot(domNode);
root.render(<Comment />);
// You can add it anywhere in the document
document.body.appendChild(domNode);

Чтобы удалить дерево React из узла DOM и очистить все используемые им ресурсы, вызовите root.unmount.

1
root.unmount();

Это особенно полезно, если ваши компоненты React находятся внутри приложения, написанного на другом фреймворке.

Обновление корневого компонента

Вы можете вызывать render более одного раза для одного и того же корня. Пока структура дерева компонентов соответствует тому, что было отображено ранее, React будет сохранять состояние. Обратите внимание, что вы можете вводить данные, что означает, что обновления от повторных вызовов render каждую секунду в этом примере не являются разрушительными:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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);
1
2
3
4
5
6
7
8
export default function App({ counter }) {
    return (
        <>
            <h1>Hello, world! {counter}</h1>
            <input placeholder="Type something here" />
        </>
    );
}

Очень редко приходится вызывать render несколько раз. Обычно вместо этого ваши компоненты будут обновлять состояние.

Устранение неполадок

Я создал корень, но ничего не отображается

Убедитесь, что вы не забыли на самом деле создать ваше приложение в корне:

1
2
3
4
5
import { createRoot } from 'react-dom/client';
import App from './App.js';

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

Пока вы этого не сделаете, ничего не будет отображаться.

Я получаю ошибку: "Target container is not a DOM element"

Эта ошибка означает, что все, что вы передаете в createRoot, не является узлом DOM.

Если вы не уверены в том, что происходит, попробуйте записать лог:

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

Например, если domNode равен null, это означает, что getElementById вернул null. Это произойдет, если в документе нет узла с заданным ID на момент вашего вызова. Причин может быть несколько:

  1. Идентификатор, который вы ищете, может отличаться от идентификатора, который вы использовали в HTML-файле. Проверьте, нет ли опечаток!
  2. Тег <script> вашего пакета не может "увидеть" узлы DOM, которые появляются после него в HTML.

Другой распространенный способ получить эту ошибку - написать createRoot(<App />) вместо createRoot(domNode).

Я получаю ошибку: "Функции не действительны как дочерние React"

Эта ошибка означает, что все, что вы передаете в root.render, не является компонентом React.

Это может произойти, если вы вызываете root.render с Component вместо <Component />:

1
2
3
4
5
// 🚩 Wrong: App is a function, not a Component.
root.render(App);

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

Или если вы передаете функцию в root.render, а не результат ее вызова:

1
2
3
4
5
// 🚩 Wrong: createApp is a function, not a component.
root.render(createApp);

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

Мой серверный рендеринг HTML создается заново

Если ваше приложение рендерится на сервере и включает первоначальный HTML, сгенерированный React, вы можете заметить, что создание корня и вызов root.render удаляет весь этот HTML, а затем заново создает все узлы DOM с нуля. Это может быть медленнее, сбрасывает фокус и позиции прокрутки, а также может потерять другие пользовательские данные.

Приложения с серверным рендерингом должны использовать hydrateRoot вместо createRoot:

1
2
3
4
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

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

Обратите внимание, что его API отличается. В частности, обычно не происходит дальнейшего вызова root.render.

Источник — https://react.dev/reference/react-dom/client/createRoot

Комментарии