React16中render和hydrate的区别

render()

ReactDOM.render(<App />, document.getElementById('root'));

render话不多说就是渲染的意思,官方解释:

  • 在提供的 container 里渲染一个 React 元素,并返回对该组件的引用(或者针对无状态组件返回 null)。
  • 如果 React 元素之前已经在 container 里渲染过,这将会对其执行更新操作,并仅会在必要时改变 DOM 以映射最新的 React 元素
  • 如果提供了可选的回调函数,该回调将在组件被渲染或更新之后被执行。

注意:

  • ReactDOM.render() 会控制你传入容器节点里的内容。当首次调用时,容器节点里的所有 DOM 元素都会被替换,后续的调用则会使用 React 的 DOM 差分算法(DOM diffing algorithm)进行高效的更新。
  • ReactDOM.render() 不会修改容器节点(只会修改容器的子节点)。可以在不覆盖现有子节点的情况下,将组件插入已有的 DOM 节点中。
  • ReactDOM.render() 目前会返回对根组件 ReactComponent 实例的引用。 但是,目前应该避免使用返回的引用,因为它是历史遗留下来的内容,而且在未来版本的 React 中,组件渲染在某些情况下可能会是异步的。 如果你真的需要获得对根组件 ReactComponent 实例的引用,那么推荐为根元素添加 callback ref

hydrate()

与 render() 相同,但它用于在 ReactDOMServer 渲染的容器中对 HTML 的内容进行 hydrate 操作。

hydrate基本上用于SSR(服务器端渲染)。 SSR为您提供了从服务器附带的框架或HTML标记,因此,第一次在页面加载时不为空白,搜索引擎机器人可以将其索引为SEO(SSR的一个用例)。 因此,hydrate会将JS添加到您的页面或要应用SSR的节点。 这样您的页面才能响应用户执行的事件。

渲染用于在客户端浏览器Plus上渲染组件,如果尝试将hydrate替换为render,则会收到警告,提示render已弃用,在SSR情况下无法使用。 由于它比水合物慢,因此将其除去。

为什么在服务端渲染的时候不采用render?

在react15中,当服务端和客户端渲染不一致时,render会做dom patch,使得最后的渲染内容和客户端一致,否则这会使得客户端代码陷入混乱之中,如下的代码就会挂掉。

import React from 'react';

export default class Admin extends React.Component {
  componentDidMount() {
    const container = document.querySelector('.client');
    container.innerHTML = 'this is client';
  }
  render() {
    const content = __IS_CLIENT__ ? 'client' : 'server';
    return (
      <div className={content}>
        {content}
      </div>
    );
  }
}

render(React15)

在React 在浏览器端渲染之后,会把内容和服务器端给的 HTML 做一个比对。如果完全一样,那最好,接着用服务器端 HTML 就好了;如果有一丁点不一样,就会立刻丢掉服务器端的 HTML,重新渲染浏览器端产生的内容,结果就是用户可以看到界面闪烁。因为 React 抛弃的是整个服务器端渲染内容,组件树越大,这个闪烁效果越明显。

render遵从客户端渲染虽然保证了客户端代码的一致性,但是其需要对整个应用做dom diff和dom patch,其花销仍然不小。在React16中,为了减小开销,和区分render的各种场景,其引入了新的api,hydrate。

hydrate的策略与render的策略不一样,其并不会对整个dom树做dom patch,其只会对text Content内容做patch,对于属性并不会做patch。上面的代码在hydrate和render下会有两种不同的结果。

render(React16)

服务端渲染使用react16的render时,官方给到的解释:

使用 ReactDOM.render() 对服务端渲染容器进行 hydrate 操作的方式已经被废弃,并且会在 React 17 被移除。作为替代,请使用 hydrate()

React 在 v16 之后使用render不再要求整个组件树两端渲染结果分毫不差,但是如果发生不一致,依然会抛弃局部服务器端渲染结果。

总之,如果用服务器端渲染,一定要让服务器端塞给 React 组件的数据和浏览器端一致

为了达到这一目的,必须把传给 React 组件的数据给保留住,随着 HTML 一起传递给浏览器网页,这个过程,叫做“脱水”(Dehydrate);在浏览器端,就直接拿这个“脱水”数据来初始化 React 组件,这个过程叫“注水”(Hydrate)。

服务端渲染采用hydrate

如上代码在采用hydrate(React16)的结果:

 hydrate将textContent使用了客户端渲染结果,属性仍然是服务端的结果 。

React 希望服务端与客户端渲染的内容完全一致。React 可以弥补文本内容的差异,但是你需要将不匹配的地方作为 bug 进行修复

在React16的源码中

调用render和hydrate时都会调用legacyRenderSubtreeIntoContainer,render传的是false,hydrate传的是true,hydrate是true会触发强制融合,render虽然是false,会调用一个方法去判断是否需要触发强制融合,但是后续这个方法会被移除所以还是需要使用hydrate。

总结来说:

  • 采用React15的render在服务端渲染的时候如果服务器端与客户端节点不一致,服务器端的节点将完全被废弃掉重新渲染并采用客户端的节点。
  • 采用React16的render在服务端渲染的时候如果服务器端与客户端节点不一致,仅仅是尝试修改不匹配的HTML子树,而不是修改整个HTML树,同时官方给予警告:render() 对服务端渲染容器进行 hydrate 操作的方式已经被废弃,并且会在 React 17 被移除。作为替代,请使用 hydrate()
  • 这种变化对用户不会有影响,调用render()/hydrate()React 16不会修改SSR生成的不匹配HTML。这一项性能优化意味着你需要额外确保修复在开发模式下的所有警告。
  • 采用React16的hydrate时,hydrate的策略与render的策略不一样,其并不会对整个dom树做dom patch,其只会对text Content内容做patch

服务端和客户端之间的差异

  1. 服务端和客户端的运行环境不一样,所支持的语法也不一样。
  2. 服务端无法支持图片、css等资源文件。
  3. 服务端缺乏BOM和DOM环境,服务端下无法访问window,navigator等对象。
  4. 服务端中所有用户公用一个global环境,客户端每个用户都有自己的global环境。

为什么要服务器端渲染

相比于浏览器端渲染,服务器端渲染的好处是:

1.可以缩短“第一有意义渲染时间”

如果完全依赖于浏览器端渲染,那么服务器端返回的 HTML 就是一个空荡荡的框架和对 JavaScript 的应用,然后浏览器下载 JavaScript,再根据 JavaScript 中的 AJAX 调用获取服务器端数据,再渲染出 DOM 来填充网页内容,总共需要三个 HTTP 或 HTTPS 请求。

如果使用服务器端渲染,第一个 HTTP/HTTPS 请求返回的 HTML 里就包含可以渲染的内容了,这样用户第一时间就会感觉到“有东西画出来了”,这样的感知性能更好。

    2.更好的搜索引擎优化(seo优化)

React 16 可以处理数组、字符串和数字

在React 15中,组件的render方法必须返回一个简单的React元素。而在React 16中,客户端渲染的render方法允许组件返回字符串、数字或一组元素组成的数组。显然,React 16服务端渲染方法hydrate方法也支持该特性:

class App extends React.Component {
  render() {
    return [
      <div key="1">first element</div>, 
      <div key="2">second element</div>
    ];
  }
}

这种方式有助于消除用于包裹React组件的divspan,有助于减小HTML文件体积。

©️2020 CSDN 皮肤主题: 黑客帝国 设计师:上身试试 返回首页