hydrateRoot

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

const root = hydrateRoot(domNode, reactNode, options?)

Посилання

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

  • опція опцій: Об'єкт з опціями для цього кореня React.

    • optional onRecoverableError: Зворотний виклик, що виконується, коли React автоматично відновлюється після помилок.
    • .
    • optional 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 /> у гідратованому корені .

Дивіться більше прикладів нижче.

Параметри

  • reactNode: "Вузол React", який ви хочете оновити. Зазвичай це буде фрагмент JSX на кшталт <App />, але ви також можете передати React-елемент, побудований за допомогою createElement(), рядок, число, null або undefined.

Повернення

root.render повертає undefined.

Застереження

  • Якщо ви викликаєте root.render до того, як корінь завершить гідратацію, React очистить наявний серверний HTML-вміст і перемкне весь корінь на клієнтський рендеринг.

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, вам потрібно гідратувати його на клієнтській стороні.

"]]" class="language-js">import { hydrateRoot } from 'react-dom/client';

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

Це призведе до гідратації серверного HTML всередині вузла DOM браузера</CodeStep> з <CodeStep data-step="2">React-компонент</CodeStep> для вашої програми. Зазвичай, ви робите це один раз під час запуску. Якщо ви використовуєте фреймворк, він може зробити це за вас.</p> <p>Щоб гідратувати ваш застосунок, React "прикріпить" логіку ваших компонентів до початкового згенерованого HTML з сервера. Гідратація перетворює початковий HTML-знімок з сервера на повністю інтерактивний застосунок, який запускається у браузері.</p> </MaxWidth> <Пісочний пакет> <pre><code data-meta="public/index.html" class="language-html"><!-- HTML-вміст всередині <div id="root">...</div> згенеровано з App за допомогою react-dom/server. --> <div id="root"><h1>Привіт, світе!</h1><button>Ви натиснули на мене <!-- -->0<!-- --> разів</button></div>

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

hydrateRoot(
  document.getElementById('root'),
  <App />
);
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>
  );
}

Вам не потрібно викликати 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}:

<!--
  HTML content inside <div id="root">...</div>
  was generated from App by react-dom/server.
-->
<div id="root"><h1>Current Date: <!-- -->01/01/2020</h1></div>
import './styles.css';
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

hydrateRoot(document.getElementById('root'), <App />);
export default function App() {
  return (
    <h1 suppressHydrationWarning={true}>
      Current Date: {new Date().toLocaleDateString()}
    </h1>
  );
}

Це працює лише на один рівень вглиб і призначено для аварійного виходу. Не зловживайте ним. Якщо це не текстовий вміст, React все одно не намагатиметься його виправити, тому він може залишатися неузгодженим до наступних оновлень.


Робота з різним клієнтським та серверним вмістом

Якщо вам навмисно потрібно відрендерити щось різне на сервері та клієнтській стороні, ви можете зробити двопрохідний рендеринг. Компоненти, які рендеритимуть щось інше на клієнтській стороні, можуть читати змінну стану на кшталт isClient, яку ви можете встановити як true в ефекті:

<!--
  HTML content inside <div id="root">...</div>
  was generated from App by react-dom/server.
-->
<div id="root"><h1>Is Server</h1></div>
import './styles.css';
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

hydrateRoot(document.getElementById('root'), <App />);
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 збереже стан. Зверніть увагу, як ви можете вводити вхідні дані, що означає, що оновлення від повторюваних викликів рендерингу щосекунди у цьому прикладі не є деструктивними:

<!--
  All HTML content inside <div id="root">...</div> was
  generated by rendering <App /> with react-dom/server.
-->
<div id="root"><h1>Hello, world! <!-- -->0</h1><input placeholder="Type something here"/></div>
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);
export default function App({counter}) {
  return (
    <>
      <h1>Hello, world! {counter}</h1>
      <input placeholder="Type something here" />
    </>
  );
}

Виклик root.render в гідратованому корені є рідкістю. Зазвичай замість цього ви оновлюєте стан всередині одного з компонентів.