hydrateRoot
hydrateRoot позволяет отображать компоненты React внутри узла DOM браузера, содержимое HTML которого было ранее сгенерировано с помощью react-dom/server.
const root = hydrateRoot(domNode, reactNode, options?)
- Справочник
-
Использование
- Гидратация HTML, сгенерированного на сервере
- Гидратация всего документа
- Подавление неизбежных ошибок несоответствия гидратации
- Обработка различного содержимого клиента и сервера
- Обновление компонента корневого узла гидратации
- Отображение диалогового окна для неперехваченных ошибок
- Отображение ошибок граничных элементов
- Отображение диалогового окна для восстанавливаемых ошибок несоответствия гидратации
- Отладка
Справочник
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 присоединится к HTML, который существует внутри domNode, и возьмет на себя управление DOM внутри него. Приложение, полностью построенное с помощью React, обычно содержит только один hydrateRoot вызов со своим корневым компонентом.
См. дополнительные примеры ниже.
Параметры
-
domNode: Элемент DOM, который был отрисован как корневой элемент на сервере. -
reactNode: «Узел React», используемый для отрисовки существующего HTML. Обычно это фрагмент JSX, например<App />, который был отрисован с помощью методаReactDOM Server, такого какrenderToPipeableStream(<App />). -
необязательно
options: Объект с параметрами для этого корня React.-
Только Canary необязательно
onCaughtError: Обратный вызов, вызываемый, когда React перехватывает ошибку в граничном элементе. Вызывается с ошибкойerror, перехваченной граничным элементом, и объектомerrorInfo, содержащимcomponentStack. -
Только Canary необязательно
onUncaughtError: Обратный вызов, вызываемый при возникновении ошибки, не перехваченной граничным элементом. Вызывается с ошибкойerror, которая была выброшена, и объектомerrorInfo, содержащимcomponentStack. -
необязательно
onRecoverableError: Обратный вызов, вызываемый, когда React автоматически восстанавливается от ошибок. Вызывается с ошибкойerror, выброшенной React, и объектомerrorInfo, содержащимcomponentStack. Некоторые восстанавливаемые ошибки могут включать первопричину ошибки в видеerror.cause. -
необязательно
identifierPrefix: Префикс строки, используемый React для ID, генерируемыхuseId. Полезно для предотвращения конфликтов при использовании нескольких корней на одной странице. Должен совпадать с префиксом, использованным на сервере.
-
Только Canary необязательно
Возвращаемое значение
hydrateRoot возвращает объект с двумя методами: render и unmount.
Ограничения
-
hydrateRoot()ожидает, что содержимое, которое было отрисовано, будет идентично содержимому, сгенерированному на сервере. Несоответствия следует рассматривать как ошибки и исправлять их. - В режиме разработки React предупреждает о несоответствиях при гидратации. Нет гарантии, что различия в атрибутах будут исправлены в случае несоответствия. Это важно по причинам производительности, поскольку в большинстве приложений несоответствия встречаются редко, и поэтому проверка всей разметки была бы чрезмерно затратной.
- Вероятно, у приложения будет только один
hydrateRootвызов. Если вы используете фреймворк, он, возможно, выполнит этот вызов за вас. - Если ваше приложение рендерится на клиенте без предварительно отрисованного HTML, использование
hydrateRoot()не поддерживается. ИспользуйтеcreateRoot()вместо этого.
root.render(reactNode)
Вызов root.render для обновления компонента React внутри гидратированного корня React для элемента DOM браузера.
root.render(<App />); React обновит <App /> в гидратированном root.
См. дополнительные примеры ниже.
Параметры
-
reactNode: «Узел React», который вы хотите обновить. Обычно это фрагмент JSX, например<App />, но вы также можете передать элемент React, созданный с помощьюcreateElement(), строку, число,null, илиundefined.
Возвращаемое значение
root.render возвращает undefined.
Ограничения
- Если вы вызываете
root.renderдо завершения гидратации корня, React очистит существующее содержимое, сгенерированное на сервере, и переключит весь корень на рендеринг на клиенте.
root.unmount()
Вызов root.unmount для уничтожения отрисованного дерева внутри корня React.
root.unmount(); В приложении, полностью построенном с помощью React, обычно не будет вызовов root.unmount.
Это в основном полезно, если узел DOM корневого элемента React (или любой из его предков) может быть удален из DOM другим кодом. Например, представьте себе панель вкладок jQuery, которая удаляет неактивные вкладки из DOM. Если вкладка удаляется, всё внутри неё (включая корни React внутри) также будет удалено из DOM. Вам необходимо указать React «остановить» управление содержимым удалённого корня, вызвав root.unmount. В противном случае компоненты внутри удалённого корня не очистят ресурсы, такие как подписки.
Вызов 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 />); Это позволит выполнить гидрацию серверного HTML внутри узла DOM браузера с компонентом 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 вашего приложения. Для обновления интерфейса ваши компоненты будут использовать состояние вместо этого.
Опасность
Дерево React, которое вы передаёте в hydrateRoot должно генерировать тот же вывод, что и на сервере.
Это важно для пользовательского опыта. Пользователь некоторое время будет видеть сгенерированный сервером HTML, прежде чем загрузится ваш JavaScript-код. Рендеринг на сервере создаёт иллюзию более быстрого запуска приложения, показывая HTML-снимок результата. Внезапное отображение другого содержимого нарушит эту иллюзию. Вот почему результат рендеринга на сервере должен совпадать с результатом начального рендеринга на клиенте.
Наиболее распространённые причины ошибок гидратации включают:
- Лишние пробелы (например, новые строки) вокруг сгенерированного React HTML внутри корневого узла.
- Использование проверок, таких как
typeof window !== 'undefined'в вашей логике рендеринга. - Использование браузерных API, таких как
window.matchMediaв вашей логике рендеринга. - Вывод различных данных на сервере и клиенте.
React восстанавливается от некоторых ошибок гидратации, но вы должны исправить их, как и другие ошибки. В лучшем случае они приведут к замедлению работы, в худшем — обработчики событий могут быть привязаны к неправильным элементам.
Гидратация всего документа
Приложения, полностью построенные с помощью React, могут рендерить весь документ в виде JSX, включая тег <html>:
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>
);
} Для гидратации всего документа передайте глобальный объект document в качестве первого аргумента в hydrateRoot:
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> ); }
Это работает только на одном уровне вглубь и предназначено как временное решение. Не злоупотребляйте им. Если это не текстовое содержимое, React всё равно не попытается исправить его, поэтому оно может оставаться несогласованным до будущих обновлений.
Обработка различного содержимого клиента и сервера
Если вам преднамеренно нужно отобразить что-то другое на сервере и клиенте, можно выполнить двукратное рендеринг. Компоненты, которые отображают что-то другое на клиенте, могут считывать переменную состояния состояния, например isClient, которую можно установить в 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> ); }
Таким образом, начальный этап рендеринга отобразит то же самое содержимое, что и на сервере, избегая несоответствий, но сразу после гидратации будет выполнен дополнительный этап синхронно.
Опасная ситуация
Этот подход замедляет гидратацию, поскольку вашим компонентам нужно выполнить рендеринг дважды. Следите за пользовательским опытом на медленных подключениях. Код JavaScript может загружаться значительно позже, чем начальный рендеринг HTML, поэтому отображение другого пользовательского интерфейса сразу после гидратации может также вызвать неудобство для пользователя.
Обновление компонента корневого узла после гидратации
После завершения гидратации корневого узла можно вызвать 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 для гидратированного корневого узла. Обычно вы будете обновлять состояние внутри одного из компонентов.
Отображение диалогового окна для неперехваченных ошибок
Кандидат
onUncaughtError доступен только в последней версии React Canary.
По умолчанию 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 — это функция, вызываемая с двумя аргументами:
- Ошибка error, которая была сгенерирована.
- Объект 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 }); } } });
Отображение ошибок граничных значений
Кандидат
onCaughtError доступен только в последней версии React Canary.
По умолчанию 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 — это функция, вызываемая с двумя аргументами:
- Ошибка error, которая была перехвачена границей.
- Объект 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 — это функция, вызываемая с двумя аргументами:
- Ошибка error, сгенерированная React. Некоторые ошибки могут содержать первопричину как error.cause.
- Объект errorInfo, содержащий componentStack ошибки.
Для отображения диалоговых окон ошибок при несоответствиях в гидратации можно использовать параметр 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»
Частая ошибка заключается в передаче опций для hydrateRoot в root.render(...):
Для исправления передайте параметры корневого узла в hydrateRoot(...), а не в root.render(...):
// 🚩 Wrong: root.render only takes one argument.
root.render(App, {onUncaughtError});
// ✅ Correct: pass options to createRoot.
const root = hydrateRoot(container, <App />, {onUncaughtError});
© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://18.react.dev/reference/react-dom/client/hydrateRoot