Я не маю нічого конкретного додати до того, що було сказано вище про використання hydrate
, але, намагаючись дізнатись про це, я зібрав невеликий приклад, тому ось робота для тих, хто вважає це корисним.
Мета
Обслуговуйте дві сторінки, одну, яка використовує, ReactDOM.hydrate
та іншу, яка використовує ReactDOM.render
. Вони залежатимуть від деяких компонентів реакції, записаних у JSX, які завантажуються <script>
тегами з урахуванням штучної затримки (сервером) для ілюстрації різниці між hydrate
і render
.
Основна структура
- Один файл, який має HTML "скелет"
- Один файл із користувацькими компонентами React, написаними у форматі JSX
- Один сценарій, який генерує всі сторінки для використання сервером
- Один сценарій для запуску сервера
Результати
Після того, як я згенерував сторінки та запустив сервер, я заходжу до 127.0.0.1
мене і отримую заголовок гідрат , кнопку та два посилання. Я можу натиснути кнопку, але нічого не відбувається. Через кілька хвилин документ закінчується, і кнопка починає рахувати мої кліки. Потім я натискаю на посилання "render". Тепер сторінка, яку мені представили, має візуалізацію заголовка та два посилання, але жодної кнопки. Через кілька хвилин кнопка з’являється і негайно реагує.
Пояснення
На сторінці "гідрат" вся розмітка негайно відображається, оскільки на сторінку подається весь необхідний html. Кнопка не відповідає, оскільки ще немає підключених зворотних дзвінків. Після components.js
завершення завантаження load
подія запускається з window
і зворотні виклики пов'язані з hydrate
.
На сторінці "візуалізації" розмітка кнопок не відображається на сторінці, а лише вводиться ReactDOM.render
, тому її не видно відразу. Зверніть увагу, як зовнішній вигляд сторінки різко змінюється сценарієм, який остаточно завантажується.
Джерело
Ось користувацький компонент реакції, який я використовую. Він буде використовуватися сервером у вузлі з реагуванням на статично відображаються компоненти, а також буде динамічно завантажуватися з сервера для використання на сторінках (це мета перевірки exports
та React
об'єктів на початку файлу).
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
, показаного далі.
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
функцію, згадану раніше.
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>
`;
}
Нарешті, власне сервер
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') {
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');