В чем разница между hydrate() и render() в React 16?

Я прочитал документацию, но я не совсем понял разницу между hydrate() а также render() в реакции 16.

я знаю hydrate() используется для объединения SSR и рендеринга на стороне клиента.

Может кто-нибудь объяснить, что такое увлажняющий и в чем разница в ReactDOM?

7 ответов

Решение

Из документов ReactDOMServer (выделено мое):

Если вы позвоните ReactDOM.hydrate() на узле, который уже имеет разметку, представленную сервером, React сохранит ее и подключит только обработчики событий, что позволит вам получить очень эффективную работу при первой загрузке.

Текст, выделенный жирным шрифтом, является основным отличием. render может изменить ваш узел, если есть разница между исходным DOM и текущим DOM. hydrate будет прикреплять только обработчики событий.

Из выпуска Github, который представил hydrate как отдельный API:

Если это ваш начальный DOM <div id="container"><div class="spinner">Loading...</div></div> а затем позвоните ReactDOM.render(<div class="myapp"><span>App</span></div>, document.getElementById('container')) намереваясь сделать на стороне клиента только рендеринг (не гидратацию). Тогда вы заканчиваете <div id="container"><div class="spinner"><span>App</span></div></div>, Потому что мы не исправляем атрибуты.

Просто к вашему сведению причина, по которой они не исправили атрибуты

... Это будет очень медленно для гидратации в нормальном режиме гидратации и замедлит первоначальный рендеринг в дерево без SSR.

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

Цель

Обслужить две страницы, одна из которых использует ReactDOM.hydrate и тот, который использует ReactDOM.render. Они будут зависеть от некоторых компонентов реакции, написанных на JSX, которые загружаются<script> теги, заданные искусственной задержкой (сервером), чтобы проиллюстрировать разницу между hydrate а также render.

Базовая структура

  1. Один файл со "скелетом" HTML
  2. Один файл с пользовательскими компонентами React, написанными на JSX
  3. Один скрипт, который генерирует все страницы для использования сервером
  4. Один скрипт для запуска сервера

Полученные результаты

После создания страниц и запуска сервера я перехожу к 127.0.0.1и мне представлены гидрат заголовка, кнопка и две ссылки. Я могу нажать кнопку, но ничего не происходит. Через несколько секунд загрузка документа завершится, и кнопка начнет отсчет моих нажатий. Затем я нажимаю ссылку "визуализировать". Теперь у страницы, которую я представляю, есть рендер заголовка и две ссылки, но нет кнопки. Через несколько секунд кнопка появляется и сразу же начинает действовать.

Объяснение

На "гидратной" странице сразу же отображается вся разметка, потому что весь необходимый HTML-код передается вместе со страницей. Кнопка не отвечает, потому что обратные вызовы еще не подключены. однаждыcomponents.js заканчивает загрузку, load событие начинается с window и обратные вызовы связаны с hydrate.

На странице "рендеринга" разметка кнопки не обслуживается страницей, а только вводится ReactDOM.render, поэтому это не сразу видно. Обратите внимание на то, как внешний вид страницы резко меняется после загрузки скрипта.

Источник

Вот пользовательский компонент реакции, который я использую. Он будет использоваться сервером в узле для реакции на компоненты статической визуализации, а также будет динамически загружаться с сервера для использования на страницах (это цель проверкиexports а также React объекты в начале файла).

// components.jsx

var exports = typeof(exports) == 'object' ? exports : {};
var React = typeof(React) == 'object' ? React : require('react');

function MyButton(props) {
  [click, setClick] = React.useState(0);
  function handleClick() { setClick(click + 1); }
  return (
    <button onClick={handleClick}>Clicked: {click}</button>
  );
}

exports.MyButton = MyButton;

This is the script used to generate all the pages required for the server. First, babel is used to transpile components.jsx into javascript, then these components are used, along with React and ReactDOMServer, to create the actual pages. These pages are created with the fuction getPage which is exported from the file pageTemplate.js, shown next.

// genScript.js

let babel          = require('@babel/core');
let fs             = require('fs');
let ReactDOMServer = require('react-dom/server');
let React          = require('react');
let pageTemplate   = require('./pageTemplate.js');

script = babel.transformFileSync(
  'components.jsx', 
  {presets : [['@babel/react']]}
);

fs.writeFileSync('components.js',script.code);
let components = require('./components.js');

hydrateHTML = pageTemplate.getPage(
  'MyButton',
  ReactDOMServer.renderToString(React.createElement(components.MyButton)),
  'hydrate'
);

renderHTML = pageTemplate.getPage(
  'MyButton',
  '',
  'render'
);

fs.writeFileSync('hydrate.html',hydrateHTML);
fs.writeFileSync('render.html',renderHTML);

This file just exports the getPage function mentioned previously.

// pageTemplate.js

exports.getPage = function(
  reactElementTag,
  reactElementString,
  reactDOMMethod
  ) {
  return `
  <!DOCTYPE html>
  <html>
    <head>
      <meta charset="utf-8" />
      <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js" defer></script>
      <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" defer></script>
      <script src="./components.js" defer></script>
    </head>
    <body> 
      <h1>${ reactDOMMethod }</h1>
      <div id="react-root">${ reactElementString }</div> 
      <a href="hydrate.html">hydrate</a>
      <a href="render.html">render</a>
    </body>
    <script>
      window.addEventListener('load', (e) => {
        ReactDOM.${ reactDOMMethod }(
          React.createElement(${ reactElementTag }),
          document.getElementById('react-root')
        );
      });
    </script>
  </html>
  `;
}

Finally, the actual server

// server.js

let http = require('http');
let fs   = require('fs');

let renderPage       = fs.readFileSync('render.html');
let hydratePage      = fs.readFileSync('hydrate.html');
let componentsSource = fs.readFileSync('components.js');

http.createServer((req, res) => {
  if (req.url == '/components.js') {
    // artificial delay
    setTimeout(() => {
    res.setHeader('Content-Type','text/javascript');
    res.end(componentsSource);
    }, 2000);
  } else if (req.url == '/render.html') {
    res.end(renderPage);
  } else {
    res.end(hydratePage);
  }
}).listen(80,'127.0.0.1');

Гидрат в основном используется в случае SSR(рендеринга на стороне сервера). SSR дает вам скелет или HTML-разметку, которая отправляется с сервера, чтобы в первый раз, когда ваша страница загружалась, она не была пустой, и поисковые роботы могли индексировать ее для SEO(вариант использования SSR). Таким образом, гидрат добавляет JS к вашей странице или узлу, к которому применяется SSR. Чтобы ваша страница реагировала на события, выполненные пользователем.

Рендеринг используется для рендеринга компонента в браузере на стороне клиента. Плюс, если вы попытаетесь заменить гидрат рендером, вы получите предупреждение о том, что рендеринг устарел и не может использоваться в случае SSR. он был удален из-за того, что он медленный по сравнению с гидратом.

В дополнение к выше...

ReactDOM.hydrate () аналогичен render(), но используется для гидратации (прикрепления прослушивателей событий) контейнера, содержимое HTML которого было обработано ReactDOMServer. React попытается присоединить прослушиватели событий к существующей разметке.

Использование ReactDOM.render() для гидратации контейнера, отображаемого на сервере, не рекомендуется из-за медлительности и будет удалено в React 17. Вместо этого используйте hydrate ().

Весь процесс возврата функциональности обратно в HTML, который уже был представлен в React на стороне сервера, называется гидратацией.

Таким образом, процесс повторного рендеринга по ранее обработанному HTML называется гидратацией.

Так что, если мы попытаемся увлажнить наше приложение, позвонив ReactDOM.render() это должно быть сделано по телефону ReactDOM.hydrate(),

Render удалит что-либо в указанном элементе (в большинстве случаев называется "root") и перестроит его, в то время как hydrate сохранит все, что уже находится внутри указанного элемента, и будет строить из него, ускоряя загрузку начальной страницы.

Hydrate () используется, когда мы хотим отобразить ваше приложение React на стороне сервера и гидратировать пакет JavaScript на стороне клиента, что делает наше приложение быстрым, а также позволяет поисковым системам сканировать ваши страницы в целях SEO.

Но что произойдет, если мы изменим метод рендеринга на гидрат

Ошибка ясно показывает, что если ваше приложение не использует рендеринг на стороне сервера (SSR), используйте рендеринг reactdom для запуска рендеринга на стороне клиента. Прочитать эту статью

Другие вопросы по тегам