Spec-Zone.ru › React

hydrateRoot

hydrateRoot позволяет отображать компоненты React внутри узла DOM браузера, HTML-содержимое которого было предварительно сгенерировано с помощью react-dom/server.

const root = hydrateRoot(domNode, reactNode, options?)
  • Ссылка
    • hydrateRoot(domNode, reactNode, options?)
    • root.render(reactNode)
    • root.unmount()
  • Использование
    • Гидратация серверно-отрендеренного HTML
    • Гидратация всего документа
    • Подавление неизбежных ошибок несоответствия гидрации
    • Обработка разного клиентского и серверного содержимого
    • Обновление гидратированного корневого компонента
    • Показать диалог для неперехваченных ошибок
    • Отображение ошибок граничных элементов
    • Показать диалог для восстановимых ошибок несоответствия гидрации
  • Отладка
    • Ошибка: «Вы передали второй аргумент в root.render»

Ссылка

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.

    • необязательно onCaughtError: Обратный вызов, вызываемый, когда React перехватывает ошибку в элементе Error Boundary. Вызывается с перехваченной error ошибкой элемента Error Boundary и объектом errorInfo, содержащим componentStack.
    • необязательно onUncaughtError: Обратный вызов, вызываемый, когда ошибка была брошена и не перехвачена элементом Error Boundary. Вызывается с брошенной error ошибкой и объектом errorInfo, содержащим componentStack.
    • необязательно onRecoverableError: Обратный вызов, вызываемый, когда React автоматически восстанавливается от ошибок. Вызывается с брошенной error ошибкой React и объектом errorInfo, содержащим componentStack. Некоторые восстановимые ошибки могут включать исходную причину ошибки в виде error.cause.
    • необязательно identifierPrefix: Префикс строки, который React использует для идентификаторов, сгенерированных с помощью useId. Полезно для предотвращения конфликтов при использовании нескольких корней на одной странице. Должен совпадать с префиксом, используемым на сервере.

Возвращаемые значения

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-снимок его результата. Внезапное отображение другого содержимого нарушает эту иллюзию. Вот почему выходные данные серверного рендеринга должны соответствовать начальному выходному результату рендеринга на клиенте.

К наиболее распространённым причинам ошибок гидрации относятся:

  • Дополнительные пробелы (например, переводы строк) вокруг HTML, сгенерированного React, внутри корневого узла.
  • Использование проверок, таких как 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 в элементе Effect:

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 на корневом элементе после гидратации. Обычно вы обновляете состояние внутри одного из компонентов.

Показать диалог для необработанных ошибок

По умолчанию 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 — это функция, вызываемая с двумя аргументами:

  1. Выброшенная ошибка.
  2. Объект errorInfo, содержащий стек вызовов ошибки.

Вы можете использовать параметр 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
      });
    }
  }
});

Отображение ошибок Error Boundary

По умолчанию React регистрирует все ошибки, перехваченные Error Boundary, в console.error. Чтобы изменить это поведение, вы можете указать необязательный onCaughtError параметр корня для ошибок, перехваченных Error Boundary:

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 — это функция, вызываемая с двумя аргументами:

  1. Ошибка, перехваченная граничной областью.
  2. Объект errorInfo, содержащий стек вызовов ошибки.

Вы можете использовать параметр 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 — это функция, вызываемая с двумя аргументами:

  1. Ошибка, которую выбрасывает React. Некоторые ошибки могут содержать исходную причину в качестве error.cause.
  2. Объект errorInfo, содержащий стек вызовов ошибки.

Вы можете использовать параметр 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(...):

Консоль
Предупреждение: Вы передали второй аргумент в 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://react.dev/reference/react-dom/client/hydrateRoot

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API