React-简单组件到浏览器DOM的渲染

By
写代码

在【React-简单组件的挂载(mount)过程】的2.6)里提到了组件最后从ReactElement到HTML-DOM的转换过程,但是没展开。本周趁着还熟,这篇填坑。

首先,简单画一下本篇的数据结构
dom-render

前面挂载一篇说过,从ReactCompositeComponent一步一步调用mountComponent,最后会到最内层的ReactDomComponent.mountComponent,本篇直接从这里往下面走。

接着根据el信息创建用于渲染的主树(lazyTree)。

至于这里为什么叫lazyTree?这部分的说明放到最后。

实例化子节点

接着开始依次实例化子节点。并最后填充到主树上。

这一通操作之后,会取到最终实例化的子节点树,由一个个的ReactDOMTextElement组成。

最后父级的lazyTree长这样

如果用f12查看元素,会看到,最终的节点是由两段react-text注释包起来的

为什么要用Comment包起来?这部分也放在最后说。

渲染浏览器DOM

在这一步操作之后,会逐层返回,最后调用最外层的

这里分为2个小步骤:
1) removeChild递归清空container容器内容;
2) 在#container节点上调用insertBefore插入lazyTree.node

这样,到浏览器的DOM就渲染完成了。

小记

1、为什么需要lazyTree?

lazyTree主要解决的是在IE(8-11)和Edge浏览器中,插入节点的效率问题。总的来说,在上述IE系列浏览器中,一个一个插入无子孙的节点,效率要远高于插入一整个序列化完整的节点树。

关于二者的效率差异和说明,可以看这里:innerHTML vs. createElement vs. cloneNode

具体来说,在上述IE系列里,从最“孙子”的节点开始往上,挨个parentNode.insertBefore,会比较快。在非浏览器里,可以从下网上,parentNode.appendChild,效率也很高。差别很明显,一个自顶向下,一个自下向上。所以可以看到lazyTree生成的结构是这样

这个结构里,node用于非IE浏览器的DOM操作,里面直接就是搞好的HTML节点。而children用于IE系列,因为需要记录下来回去的路径,才能遍历。

说明二者操作差异的函数,在DOMLazyTree.queueChild

最后insertTreeBefore,会判断是操作children插入节点,还是直接插入node

2、为什么要用Commenttext包起来?

答案是避免不必要的遍历。

前面可以看到,每一个ReactDOMTextComponent都包含一个指向Comment的链接,反向链接也由。这就相当于从虚拟节点到实际节点的双向链接,以保证每个节点都是立即可达的。

但是,单纯的一段text,没有办法添加附加属性来创建反向链接,所以这里使用了Comment来承载节点信息。

关于Comment的创建,使用的是Document.createComment(),可能这个方法不常用,具体说明可看MDN: createComment

0

Comments: 5

  1. 学习啦

    01月02日
  2. 新年快乐。

    01月02日
  3. 新年快乐哈~~

    02月11日
  4. 膜拜大佬!

    02月15日
  5. 简洁实用,好文章!

    02月26日

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

:razz: