我已经阅读了文档,但我并没有真正理解React 16hydrate()
之间的区别。render()
我知道hydrate()
用于结合 SSR 和客户端渲染。
有人可以解释什么是保湿,那么 ReactDOM 有什么区别?
我已经阅读了文档,但我并没有真正理解React 16hydrate()
之间的区别。render()
我知道hydrate()
用于结合 SSR 和客户端渲染。
有人可以解释什么是保湿,那么 ReactDOM 有什么区别?
从ReactDOMServer文档(强调我的):
如果你调用
ReactDOM.hydrate()
一个已经有这个服务器渲染标记的节点,React 将保留它并且只附加事件处理程序,让你有一个非常高性能的首次加载体验。
粗体字是主要区别。render
如果初始 DOM 和当前 DOM 之间存在差异,可能会更改您的节点。hydrate
只会附加事件处理程序。
从作为单独 API引入的 Github 问题中hydrate
:
如果这是您的初始 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 编写的 react 组件,这些组件由<script>
标签加载,并给予人为延迟(由服务器)来说明hydrate
和render
.
在生成页面并运行服务器后,我会转到127.0.0.1
标题hydrate、一个按钮和两个链接。我可以单击按钮,但没有任何反应。片刻之后,文档完成加载,按钮开始计算我的点击次数。然后我点击“渲染”链接。现在,我看到的页面有标题渲染和两个链接,但没有按钮。片刻之后,按钮出现并立即响应。
在“水合物”页面上,所有标记都会立即呈现,因为所有必要的 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');
Hydrate 主要用于 SSR(服务器端渲染)。SSR 为您提供从服务器发送的骨架或 HTML 标记,以便在您的页面第一次加载时它不是空白的,并且搜索引擎机器人可以为 SEO(SSR 的一个用例)索引它。因此 hydra 将 JS 添加到您的页面或应用 SSR 的节点中。以便您的页面响应用户执行的事件。
渲染用于在客户端浏览器上渲染组件另外,如果您尝试用渲染替换水合物,您将收到一个警告,即渲染已被弃用,并且在 SSR 的情况下无法使用。它被删除是因为它比水合物慢。
除了以上...
ReactDOM.hydrate()
与 相同render()
,但它用于水合(附加事件侦听器)其 HTML 内容由 ReactDOMServer 呈现的容器。React 将尝试将事件侦听器附加到现有标记。
由于速度慢,不推荐使用 ReactDOM.render() 来水合服务器渲染的容器,并将在React 17中删除,因此请hydrate()
改用。
将功能放回已经在服务器端 React 中呈现的 HTML 的整个过程称为水合。
因此,在曾经渲染的 HTML 上重新渲染的过程称为水合。
因此,如果我们尝试通过调用ReactDOM.render()
它应该通过调用来完成我们的应用程序ReactDOM.hydrate()
。
render 将清除指定元素中的任何内容(在大多数情况下称为“root”)并重建它,而 hydra 将保留指定元素中已经存在的任何内容并从中构建,从而使初始页面加载更快。
当我们想要在服务器端渲染你的 React 应用程序并在客户端对 JavaScript 包进行水合时使用 hydrate() ,这使我们的应用程序速度更快,还允许搜索引擎抓取你的页面以用于 SEO 目的。
但是当我们将渲染方法更改为水合物时会发生什么
该错误清楚地表明,如果您的应用程序不使用服务器端渲染(SSR),请使用 reactdom 渲染启动客户端渲染。 阅读这篇文章