React 直出实现与原理
In 未分类 on 2015年05月04日 by view: 2,426
1

前一篇文章我们介绍了虚拟 DOM 的实现与原理,这篇文章我们来讲讲 React 的直出。
比起 MVVM,React 比较容易实现直出,那么 React 的直出是如何实现,有什么值得我们学习的呢?

为什么 MVVM 不能做直出?

对于 MVVM,HTML 片段即为配置,而直出后的 HTML 无法还原配置,所以问题不是 MVVM 能否直出,而是在于直出后的片段能否还原原来的配置。下面是一个简单的例子:

上面这段 HTML 配置和数据在一起,直出后会变成:

这时候当我们失去了 name 的值改变的时候会导致页面渲染这个细节。当然,如果为了实现 MVVM 直出我们可能有另外的方法来解决,例如直出结果变成这样:

这时候我们是可以把丢失的信息找回来的,当然结构可能和我们想象的有些差别。当然还有其他问题,例如直出 HTML 不一定能反向还原数据,由于篇幅问题,这里不展开讨论。

React 如何直出?

2

如图:

  • React 的虚拟 DOM 的生成是可以在任何支持 Javascript 的环境生成的,所以可以在 NodeJS 或 Iojs 环境生成
  • 虚拟 DOM 可以直接转成 String
  • 然后插入到 html 文件中输出给浏览器便可

具体例子可以参考,https://github.com/DavidWells/isomorphic-react-example/,下面是其渲染路由的写法:

OK,我们现在知道如何利用 React 实现直出,以及如何前后端代码复用。

但还有下面几个问题有待解决:

  • 如何渲染文字节点,每个虚拟 DOM 节点是需要对应实际的节点,但无法通过 html 文件生成相邻的 Text Node,例如下面例子应当如何渲染:

  • 如何避免直出的页面被 React 重新渲染一遍?或者直出的页面和前端的数据是不对应的怎么办?

相邻的 Text Node,想多了相邻的 span 而已

1

通过一个简单的例子,我们可以发现,实际上 React 根本没用 Text Node,而是使用 span 来代替 Text Node,这样就可以实现虚拟 DOM 和直出 DOM 的一一映射关系。

重复渲染?没门

刚刚的例子,如果我们通过 React.renderToString 拿到<Test /> 可以发现是:

我们可以发现一个有趣的属性 data-react-checksum,这是啥?实际上这是上面这段 HTML 片段的 adler32 算法值。实际上调用 React.render(<MyComponent />, container); 时候做了下面一些事情:

  • 看看 container 是否为空,不为空则认为有可能是直出了结果。
  • 接下来第一个元素是否有 data-react-checksum 属性,如果有则通过 React.renderToString 拿到前端的,通过 adler32 算法得到的值和 data-react-checksum 对比,如果一致则表示,无需渲染,否则重新渲染,下面是 adler32 算法实现:

  • 如果需要重新渲染,先通过下面简单的差异算法找到差异在哪里,打印出错误:

下面是首屏渲染时的主要逻辑,可以发现 React 对首屏实际上也是通过 innerHTML 来渲染的:

最后

尝试一下下面的代码,想想 React 为啥认为这是错误的?

原创文章转载请注明:

转载自AlloyTeam:http://www.alloyteam.com/2015/05/react-zhi-chu-shi-xian-yu-yuan-li/

  1. 2016 年 5 月 17 日

    这代码高亮插件是疯了吧?让人无法看

发表评论