React SSR
React 同构的关键要素
### DOM 的一致性
前后端相同的 Component , 将输出一致地 DOM 结构
完善的 Component 属性及生命周期与客户端的 render 时机是 React 同构的关键
React 的虚拟 DOM 以对象树的形式保存在内存中,并且是可以在任何支持 JavaScript 的环境中生成的,所以可以在浏览器和 Node 中生成,这位前后端同构提供了先决条件
如上图:
在Node 是可以生成虚拟 DOM 的
虚拟 DOM 可以直接转成 String
然后插入到 HTML 文件中输出给浏览器便可
虚拟 Dom 在前后端都是以对象树的形式存在的,但在展露原型的方式确是不一样的
在浏览器里,React 通过 ReactDom 的 render 方法将虚拟 Dom 渲染到真实的 Dom 树上,生成网页
但是在 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 对象,需要做不同处理等