Яка різниця між гідратом () і рендером () у React 16?


85

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

Я знаю hydrate(), що використовується для поєднання SSR та візуалізації на стороні клієнта.

Хтось може пояснити, що таке зволоження, і яка тоді різниця у ReactDOM?


відповідь нижче, дана @tophar, є правильною, якщо ви хочете вивчити її далі, ви можете прочитати цю реакцію.org.org/docs/react-dom.html
Горах Нат

Відповіді:


80

З документації 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>

Тому що ми не виправляємо атрибути.

Просто FYI, тому що вони не виправили атрибути

... Це було б дуже повільним для гідратації в звичайному режимі гідратації та уповільнення початкового відтворення в дерево, яке не є SSR.


8
Я не розумію, чому у візуалізованому div немає div з класами з ім'ям myapp і чому там клас spinner у фінальному візуалізованому елементі
pravin poudel

2
@pravinpoudel Я думаю, що це тому, що вони не виправляють атрибути під час візуалізації на стороні клієнта. Ось чому атрибут class="spinner"залишається таким, яким він є в <div>елементі.
Гленн Мохаммад,

30

Гідрат в основному використовується у випадку SSR (візуалізація на стороні сервера). SSR надає вам скелет або розмітку HTML, що надсилається із сервера, так що вперше, коли ваша сторінка завантажується, вона не є порожньою, і боти пошукових систем можуть її індексувати для SEO (випадок використання SSR). Отже, гідрат додає JS до вашої сторінки або вузла, до якого застосовується SSR. Щоб ваша сторінка реагувала на події, які виконує користувач.

Render використовується для візуалізації компонента в браузері на стороні клієнта. Плюс, якщо ви спробуєте замінити гідрат на render, ви отримаєте попередження про те, що візуалізація застаріла і не може бути використана у випадку SSR. його видалили через повільність порівняно з гідратом.


23

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

Мета

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

Основна структура

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

Результати

Після того, як я згенерував сторінки та запустив сервер, я заходжу до 127.0.0.1мене і отримую заголовок гідрат , кнопку та два посилання. Я можу натиснути кнопку, але нічого не відбувається. Через кілька хвилин документ закінчується, і кнопка починає рахувати мої кліки. Потім я натискаю на посилання "render". Тепер сторінка, яку мені представили, має візуалізацію заголовка та два посилання, але жодної кнопки. Через кілька хвилин кнопка з’являється і негайно реагує.

Пояснення

На сторінці "гідрат" вся розмітка негайно відображається, оскільки на сторінку подається весь необхідний 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;

Це сценарій, який використовується для створення всіх сторінок, необхідних для сервера. Спочатку babel використовується для транспіляції components.jsx у javascript, потім ці компоненти використовуються разом із React та ReactDOMServer для створення фактичних сторінок. Ці сторінки створюються за допомогою функції, getPageяка експортується з файлу pageTemplate.js, показаного далі.

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

Цей файл просто експортує getPageфункцію, згадану раніше.

// 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>
  `;
}

Нарешті, власне сервер

// 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');

2
Ого. Ви в основному відповіли на питання + пояснили, як створити мінімальний статичний генератор, такий як Гетсбі. Дивовижний. Дуже дякую!
Сергій Лукін

22

На додаток до вище ...

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

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


18

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

Отже, процес рендерингу одного разу відтвореного HTML називається гідратацією.

Отже, якщо ми спробуємо гідратувати наш додаток, зателефонувавши ReactDOM.render()до цього, як передбачається, за допомогою дзвінка ReactDOM.hydrate().


1

render вимиє будь-що з зазначеного елемента (у більшості випадків називається `` root '') і відновить його, тоді як hydrate збереже все, що вже знаходиться в зазначеному елементі, і побудує з цього, роблячи швидше завантаження початкової сторінки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.