React 16 中的 hydrate() 和 render() 有什么区别?
What's the difference between hydrate() and render() in React 16?
我已经阅读了文档,但我并没有真正理解 React 16 中 hydrate()
和 render()
之间的区别。
我知道hydrate()
是用来结合SSR和客户端渲染的
谁能解释一下什么是保湿,然后 ReactDOM 有什么区别?
来自 ReactDOMServer 文档(强调我的):
If you call ReactDOM.hydrate()
on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
粗体文字是主要区别。如果初始 DOM 和当前 DOM 之间存在差异,render
可能会更改您的节点。 hydrate
只会附加事件处理程序。
来自Github issue that introduced hydrate
as a separate API:
If this is your initial DOM:
<div id="container">
<div class="spinner">Loading...</div>
</div>
and then call:
ReactDOM.render(
<div class="myapp">
<span>App</span>
</div>,
document.getElementById('container')
)
intending to do a client-side only render (not hydration).
Then you end with
<div id="container">
<div class="spinner">
<span>App</span>
</div>
</div>
Because we don't patch up the attributes.
仅供参考,他们没有修补属性的原因是
... This would be really slow to hydrate in the normal hydration mode and slow down initial render into a non-SSR tree.
除了以上...
ReactDOM.hydrate()
与 render()
相同,但它用于 hydrate(附加事件侦听器)容器 其 HTML 内容是由 ReactDOMServer 渲染。 React 将尝试将事件侦听器附加到现有标记。
使用 ReactDOM.render() 来混合服务器渲染的容器由于速度慢而被弃用,并且将在 React 17 中被删除,因此请改用 hydrate()
.
Hydrate主要用于SSR(Server side Rendering)。 SSR 为您提供了从服务器发送的框架或 HTML 标记,这样当您的页面第一次加载时它不是空白的,搜索引擎机器人可以为 SEO 索引它(SSR 的一个用例)。因此 hydrate 将 JS 添加到您的页面或应用 SSR 的节点。以便您的页面响应用户执行的事件。
Render 用于在客户端浏览器上呈现组件另外,如果您尝试用 render 替换 hydrate,您将收到一条警告,指出 render 已被弃用并且不能在 SSR 的情况下使用。它被删除是因为它比水合物慢。
将功能放回已在服务器端 React 中呈现的 HTML 的整个过程称为水合作用。
因此,在渲染过的 HTML 上重新渲染的过程称为水合作用。
因此,如果我们尝试通过调用 ReactDOM.render()
来滋润我们的应用程序,它应该通过调用 ReactDOM.hydrate()
.
来完成
对于上面所说的 hydrate
的使用,我没有任何具体要补充的内容,但在尝试了解它的过程中,我举了一个小例子,所以这是为找到的人准备的工作很有帮助。
目标
提供两个页面,一个使用 ReactDOM.hydrate
,一个使用 ReactDOM.render
。它们将依赖于一些用 JSX 编写的 React 组件,这些组件由 <script>
标签加载,人工延迟(由服务器)来说明 hydrate
和 render
之间的区别。
基本结构
- 一个文件具有 HTML "skeleton"
- 一个文件,其中包含用 JSX 编写的自定义 React 组件
- 一个脚本生成所有页面供服务器使用
- 一个脚本到 运行 服务器
结果
生成页面和 运行 服务器后,我转到 127.0.0.1
并看到 header hydrate,一个按钮和两个 link。我可以点击按钮,但没有任何反应。片刻之后,文档完成加载,按钮开始计算我的点击次数。然后我点击 "render" link。现在,我看到的页面有 header render 和两个 link,但没有按钮。片刻之后,按钮出现并立即响应。
说明
在 "hydrate" 页面上,所有标记都会立即呈现,因为页面提供了所有必要的 html。该按钮没有响应,因为还没有连接任何回调。 components.js
完成加载后,load
事件从 window
触发,回调与 hydrate
.
连接
在 "render" 页面上,按钮标记不随页面提供,而仅由 ReactDOM.render
注入,因此不会立即可见。请注意页面的外观是如何被最终加载的脚本明显改变的。
来源
这是我正在使用的自定义反应组件。它将被节点中的服务器使用,对静态渲染组件做出反应,并且还将从服务器动态加载以用于页面(这是检查 exports
和 React
objects 在文件的开头)。
// 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 来创建实际页面。这些页面是使用从文件 pageTemplate.js
导出的函数 getPage
创建的,如下所示。
// 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');
render 将清除指定元素中的所有内容(在大多数情况下命名为 'root')并重建它,而 hydrate 将保留指定元素中已经存在的所有内容并从中构建,制作初始页面加载速度更快。
hydrate() 当我们想要在服务器端呈现 React 应用程序并在客户端水化 JavaScript 包时使用,这使我们的应用程序速度更快,也允许搜索引擎抓取您的网页用于 SEO 目的。
但是当我们将渲染方法更改为水合物时会发生什么
该错误清楚地表明,如果您的应用程序未使用服务器端渲染(SSR),请使用reactdom render 启动客户端渲染。
Read this article
我已经阅读了文档,但我并没有真正理解 React 16 中 hydrate()
和 render()
之间的区别。
我知道hydrate()
是用来结合SSR和客户端渲染的
谁能解释一下什么是保湿,然后 ReactDOM 有什么区别?
来自 ReactDOMServer 文档(强调我的):
If you call
ReactDOM.hydrate()
on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
粗体文字是主要区别。如果初始 DOM 和当前 DOM 之间存在差异,render
可能会更改您的节点。 hydrate
只会附加事件处理程序。
来自Github issue that introduced hydrate
as a separate API:
If this is your initial DOM:
<div id="container">
<div class="spinner">Loading...</div>
</div>
and then call:
ReactDOM.render(
<div class="myapp">
<span>App</span>
</div>,
document.getElementById('container')
)
intending to do a client-side only render (not hydration). Then you end with
<div id="container">
<div class="spinner">
<span>App</span>
</div>
</div>
Because we don't patch up the attributes.
仅供参考,他们没有修补属性的原因是
... This would be really slow to hydrate in the normal hydration mode and slow down initial render into a non-SSR tree.
除了以上...
ReactDOM.hydrate()
与 render()
相同,但它用于 hydrate(附加事件侦听器)容器 其 HTML 内容是由 ReactDOMServer 渲染。 React 将尝试将事件侦听器附加到现有标记。
使用 ReactDOM.render() 来混合服务器渲染的容器由于速度慢而被弃用,并且将在 React 17 中被删除,因此请改用 hydrate()
.
Hydrate主要用于SSR(Server side Rendering)。 SSR 为您提供了从服务器发送的框架或 HTML 标记,这样当您的页面第一次加载时它不是空白的,搜索引擎机器人可以为 SEO 索引它(SSR 的一个用例)。因此 hydrate 将 JS 添加到您的页面或应用 SSR 的节点。以便您的页面响应用户执行的事件。
Render 用于在客户端浏览器上呈现组件另外,如果您尝试用 render 替换 hydrate,您将收到一条警告,指出 render 已被弃用并且不能在 SSR 的情况下使用。它被删除是因为它比水合物慢。
将功能放回已在服务器端 React 中呈现的 HTML 的整个过程称为水合作用。
因此,在渲染过的 HTML 上重新渲染的过程称为水合作用。
因此,如果我们尝试通过调用 ReactDOM.render()
来滋润我们的应用程序,它应该通过调用 ReactDOM.hydrate()
.
对于上面所说的 hydrate
的使用,我没有任何具体要补充的内容,但在尝试了解它的过程中,我举了一个小例子,所以这是为找到的人准备的工作很有帮助。
目标
提供两个页面,一个使用 ReactDOM.hydrate
,一个使用 ReactDOM.render
。它们将依赖于一些用 JSX 编写的 React 组件,这些组件由 <script>
标签加载,人工延迟(由服务器)来说明 hydrate
和 render
之间的区别。
基本结构
- 一个文件具有 HTML "skeleton"
- 一个文件,其中包含用 JSX 编写的自定义 React 组件
- 一个脚本生成所有页面供服务器使用
- 一个脚本到 运行 服务器
结果
生成页面和 运行 服务器后,我转到 127.0.0.1
并看到 header hydrate,一个按钮和两个 link。我可以点击按钮,但没有任何反应。片刻之后,文档完成加载,按钮开始计算我的点击次数。然后我点击 "render" link。现在,我看到的页面有 header render 和两个 link,但没有按钮。片刻之后,按钮出现并立即响应。
说明
在 "hydrate" 页面上,所有标记都会立即呈现,因为页面提供了所有必要的 html。该按钮没有响应,因为还没有连接任何回调。 components.js
完成加载后,load
事件从 window
触发,回调与 hydrate
.
在 "render" 页面上,按钮标记不随页面提供,而仅由 ReactDOM.render
注入,因此不会立即可见。请注意页面的外观是如何被最终加载的脚本明显改变的。
来源
这是我正在使用的自定义反应组件。它将被节点中的服务器使用,对静态渲染组件做出反应,并且还将从服务器动态加载以用于页面(这是检查 exports
和 React
objects 在文件的开头)。
// 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 来创建实际页面。这些页面是使用从文件 pageTemplate.js
导出的函数 getPage
创建的,如下所示。
// 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');
render 将清除指定元素中的所有内容(在大多数情况下命名为 'root')并重建它,而 hydrate 将保留指定元素中已经存在的所有内容并从中构建,制作初始页面加载速度更快。
hydrate() 当我们想要在服务器端呈现 React 应用程序并在客户端水化 JavaScript 包时使用,这使我们的应用程序速度更快,也允许搜索引擎抓取您的网页用于 SEO 目的。
但是当我们将渲染方法更改为水合物时会发生什么
该错误清楚地表明,如果您的应用程序未使用服务器端渲染(SSR),请使用reactdom render 启动客户端渲染。 Read this article