我已阅读文档,但我并不完全理解React 16中hydrate()
和render()
之间的区别。
我知道hydrate()
用于组合SSR和客户端呈现。
有人可以解释什么是保湿,然后ReactDOM有什么区别?
答案 0 :(得分:50)
来自ReactDOMServer文档(强调我的):
如果您在已经具有此服务器呈现标记的节点上调用
ReactDOM.hydrate()
, React将保留它并仅附加事件处理程序,从而允许您具有非常高性能的首次加载经验。
粗体文字是主要区别。如果初始DOM和当前DOM之间存在差异,render
可能会更改您的节点。 hydrate
只会附加事件处理程序。
来自Github issue that introduced hydrate
as a separate 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树。
答案 1 :(得分:20)
关于上述hydrate
的使用,我没有什么要补充的,但是在尝试了解这一点时,我举了一个小例子,所以这是对任何认为有用的人的工作
提供两个页面,一个页面使用ReactDOM.hydrate
,另一个页面使用ReactDOM.render
。它们将依赖于用JSX编写的一些React组件,这些组件由<script>
标签加载,并通过人为延迟(由服务器提供)来说明hydrate
和render
之间的区别。
生成页面并运行服务器后,转到127.0.0.1
,并显示标题 hydrate ,一个按钮和两个链接。我可以单击该按钮,但是什么也没有发生。片刻之后,文档完成加载,并且按钮开始计算我的点击次数。然后,我单击“渲染”链接。现在,向我显示的页面具有标题 render 和两个链接,但是没有按钮。片刻之后,该按钮出现并立即响应。
在“水合物”页面上,所有标记都将立即呈现,因为所有必需的html都随该页面一起提供。该按钮没有响应,因为还没有连接回调。 components.js
完成加载后,load
将触发window
事件,并且回调函数将与hydrate
连接。
在“渲染”页面上,按钮标记不随页面一起提供,而仅由ReactDOM.render
注入,因此不会立即可见。请注意,最终加载的脚本如何严重改变页面的外观。
这是我正在使用的自定义react组件。服务器将在节点中使用它,以对静态渲染组件做出反应,并且还将从服务器动态加载它以供页面使用(这是检查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将component.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 :(得分:9)
除了以上......
ReactDOM.hydrate()
与render()
相同,但它用于水合(附加事件侦听器)容器,其内容由ReactDOMServer呈现。 React会尝试将事件侦听器附加到现有标记。
使用ReactDOM.render()来水合服务器呈现的容器由于速度慢而被弃用,并且将在 React 17 中删除,因此请改用hydrate()
。
答案 3 :(得分:1)
在SSR(服务器端渲染)的情况下,基本上使用水合。 SSR为您提供了从服务器附带的框架或HTML标记,因此,第一次在页面加载时不为空白,搜索引擎机器人可以将其索引为SEO(SSR的一个用例)。因此,水合物会将JS添加到您的页面或要应用SSR的节点。这样您的页面才能响应用户执行的事件。
渲染用于在客户端浏览器Plus上渲染组件,如果尝试将水合物替换为渲染,则会收到警告,提示渲染已弃用,在SSR情况下无法使用。由于它比水合物慢,因此被除去。
答案 4 :(得分:1)
将功能放回到已经在服务器端React中呈现的HTML中的整个过程称为水合作用。
因此,对曾经渲染过的HTML进行重新渲染的过程称为水合。
因此,如果我们尝试通过调用ReactDOM.render()
来充水我们的应用程序,则应该通过调用ReactDOM.hydrate()
来完成。
答案 5 :(得分:1)
render将清除指定元素中的所有内容(在大多数情况下称为“ root”)并进行重建,而hydr则将保留指定元素中已经存在的所有内容并以此为基础进行构建,从而使初始页面加载速度更快。