React SSR

React 同构的关键要素

### DOM 的一致性

前后端相同的 Component , 将输出一致地 DOM 结构

完善的 Component 属性及生命周期与客户端的 render 时机是 React 同构的关键

React 的虚拟 DOM 以对象树的形式保存在内存中,并且是可以在任何支持 JavaScript 的环境中生成的,所以可以在浏览器和 Node 中生成,这位前后端同构提供了先决条件

如上图:

  1. 在Node 是可以生成虚拟 DOM 的

  2. 虚拟 DOM 可以直接转成 String

  3. 然后插入到 HTML 文件中输出给浏览器便可

虚拟 Dom 在前后端都是以对象树的形式存在的,但在展露原型的方式确是不一样的

  1. 在浏览器里,React 通过 ReactDom 的 render 方法将虚拟 Dom 渲染到真实的 Dom 树上,生成网页

  2. 但是在 Node 环境下是没有渲染引擎的,所以 React 提供了另外两个方法:ReactDOMServer.renderToString, ReactDOMServer.renderToStaticMarkup

  • ReactDOMServer.renderToString: 大多数情况应该使用这个方法,这样会为组件增加 checksum

    React 在客户端通过 checksum 判断是否需要重新render 相同则不重新render,省略创建 DOM 和挂 载DOM 的过程, 接着触发 componentDidMount 等事件来处理服务端上的未尽事宜(事件绑定等),从而加快了交互时间;不同时,组件将客户端上被重新挂载 render

    checknum 实际上是 HTML 片段的 adler32 算法值,实际上调用 React.render(<MyComponent />, container); 时候做了下面一些事情:

    container
    data-react-checksum
    var MOD = 65521;
    
    // This is a clean-room implementation of adler32 designed for detecting
    // if markup is not what we expect it to be. It does not need to be
    // cryptographically strong, only reasonably good at detecting if markup
    // generated on the server is different than that on the client.
    function adler32(data) {
      var a = 1;
      var b = 0;
      for (var i = 0; i < data.length; i++) {
        a = (a + data.charCodeAt(i)) % MOD;
        b = (b + a) % MOD;
      }
      return a | (b << 16);
    }
    
  • ReactDOMServer.renderToStaticMarkup: renderToStaticMarkup 则不会生成与 react 相关的 data-* ,也不存在 checksum,输出的 html 如下

    在客户端时组件会被重新挂载,所以该方法只当服务端上所渲染的组件在客户端不需要时才使用

不同的生命周期

在服务端上 Component 生命周期只会到 componentWillMount ,客户端则是完整的

同构时,服务端结合数据将 Component 渲染成完整的 HTML 字符串并将数据状态返回给客户端,客户端会判断是否可以直接使用或需要重新挂载

以上便是 React 在同构/服务端渲染的提供的基础条件。在实际项目应用中,还需要考虑其他边角问题,例如 服务器 端没有 window 对象,需要做不同处理等

React 服务端渲染原理及过程open in new window

Last Updated:
Contributors: 156081289@qq.com