Ich habe nichts Spezielles zu dem hinzuzufügen, was oben über die Verwendung von gesagt wurde hydrate
, aber beim Versuch, etwas darüber zu lernen, habe ich ein kleines Beispiel zusammengestellt. Hier ist die Arbeit für alle, die es hilfreich finden.
Tor
Servieren Sie zwei Seiten, eine, die verwendet, ReactDOM.hydrate
und eine, die verwendet ReactDOM.render
. Sie hängen von einigen in JSX geschriebenen Reaktionskomponenten ab, die durch <script>
Tags geladen werden und eine künstliche Verzögerung (vom Server) aufweisen, um den Unterschied zwischen hydrate
und zu veranschaulichen render
.
Grundstruktur
- Eine Datei mit dem HTML-Skelett
- Eine Datei mit den in JSX geschriebenen benutzerdefinierten React-Komponenten
- Ein Skript, das alle Seiten generiert, die der Server verwenden kann
- Ein Skript zum Ausführen des Servers
Ergebnisse
Nachdem ich die Seiten generiert und den Server ausgeführt habe, gehe ich zu 127.0.0.1
und werde mit dem Header- Hydrat , einer Schaltfläche und zwei Links angezeigt. Ich kann auf die Schaltfläche klicken, aber es passiert nichts. Nach einigen Augenblicken ist das Laden des Dokuments abgeschlossen und die Schaltfläche beginnt, meine Klicks zu zählen. Dann klicke ich auf den Link "Rendern". Jetzt hat die Seite, die mir präsentiert wird, den Header- Render und zwei Links, aber keine Schaltfläche. Nach wenigen Augenblicken erscheint die Schaltfläche und reagiert sofort.
Erläuterung
Auf der Seite "Hydrat" wird das gesamte Markup sofort gerendert, da alle erforderlichen HTML-Dateien mit der Seite bereitgestellt werden. Die Schaltfläche reagiert nicht, da noch keine Rückrufe verbunden sind. Sobald der components.js
Ladevorgang abgeschlossen ist, wird das load
Ereignis ausgelöst window
und die Rückrufe werden mit verbunden hydrate
.
Auf der Seite "Rendern" wird das Schaltflächen-Markup nicht mit der Seite bereitgestellt, sondern nur von eingefügt ReactDOM.render
, sodass es nicht sofort sichtbar ist. Beachten Sie, wie sich das Erscheinungsbild der Seite durch das endgültige Laden des Skripts grundlegend ändert.
Quelle
Hier ist die benutzerdefinierte Reaktionskomponente, die ich verwende. Es wird vom Server im Knoten verwendet, um auf statisch gerenderte Komponenten zu reagieren, und es wird auch dynamisch vom Server zur Verwendung in Seiten geladen (dies ist der Zweck der Suche nach exports
und React
Objekten am Anfang der Datei).
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;
Dies ist das Skript, mit dem alle für den Server erforderlichen Seiten generiert werden. Zuerst wird babel verwendet, um components.jsx in Javascript zu transpilieren, dann werden diese Komponenten zusammen mit React und ReactDOMServer verwendet, um die eigentlichen Seiten zu erstellen. Diese Seiten werden mit der Funktion erstellt, getPage
die aus der als pageTemplate.js
nächstes gezeigten Datei exportiert wird .
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);
Diese Datei exportiert nur die getPage
zuvor erwähnte Funktion.
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>
`;
}
Endlich der eigentliche Server
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');