React渲染机制

react渲染过程

1、React整个的渲染机制就是React会调用render()函数构建一棵Dom树,
2、在state/props发生改变的时候,render()函数会被再次调用渲染出另外一棵树,重新渲染所有的节点,构造出新的虚拟Dom tree跟原来的Dom tree用Diff算法进行比较,找到需要更新的地方批量改动,再渲染到真实的DOM上,由于这样做就减少了对Dom的频繁操作,从而提升的性能。
所以在本文我会重点介绍下react render()函数的react diff算法

一、react render()

1、在使用React进行构建应用时,我们总会有一个步骤将组建或者虚拟DOM元素渲染到真实的DOM上,将任务交给浏览器,进而进行layout和paint等步骤,这个函数就是React.render()

ReactComponent render( ReactElement element, DOMElement container, [function callback] )
React渲染机制_第1张图片

2、接收2-3个参数,并返回ReactComponent类型的对象,当组件被添加到DOM中后,执行回调。在这里涉及到了两个React类型–ReactComponent和ReactElement

(JSX中创建React元素最终会被babel转译为createElement(type, config, children),
babel根据JSX中标签的首字母来判断是原生DOM组件,还是自定义React组件)。

ReactElement类型解读
ReactElement类型通过函数React.createElement()创建,接口定义如下:
ReactElement createElement( string/ReactClass type, [object props], [children …] )

第一个参数可以接受字符串(如“p”,“div”等HTML的tag)或ReactClass,
第二个参数为传递的参数,
第三个为子元素,ReactElement有4个属性:type,ref,key,props,并且轻量,没有状态,是一个虚拟化的DOM元素
createElement()接收三个参数(type,config,children),做了一些变量初始化,接着调用了ReactElement()方法。 
ReactElement()是一个工厂方法,根据传入的参数返回一个element对象

源码流程图参考
3、 进入页面render()执行了几次
render在componentWillMount后会执行一次,会在props及state改变时执行。

  1. 首次加载
  2. setState改变组件内部state。 注意: 此处是说通过setState方法改变。
  3. 接受到新的props

二、Diff算法

react的一大特点就是虚拟DOM的diff算法,下图为diff实现流程图。
React渲染机制_第2张图片
diff算法的特点如下图:传统 diff 算法的复杂度为 O(n^3),单纯从demo看,复杂度不到n3,但实际上。React 通过制定大胆的策略,将 O(n^3) 复杂度的问题转换成 O(n) 复杂度的问题
React渲染机制_第3张图片
1、在React中,两棵DOM树只会对同一层的节点进行比较,若发现节点已不存在,则该节点及其子节点会被完全删除,不会用于进一步的比较。这样,只需要对树进行一次遍历,就能完成整个DOM树的比较
2、对于同层节点,React在数组遍历的增减关键字Key,若节点本身完全相同(类型相同,属性相同),只是位置不同,则React只需要考虑同层节点的位置变换,不需要进行节点的销毁和重新创建
React渲染机制_第4张图片
3、对于不同层的节点,只能销毁和重新创建
React渲染机制_第5张图片
1)节点类型不同:
当在树中的同一位置前后的节点类型不同,React会直接删除原节点,然后创建并插入新的节点。
注意:删除节点即彻底销毁该节点,也就是说,后续不会查找是否有另外一个节点等同于删除的该节点。如果删除的该节点有子节点,那么子节点也会被删除。这也是diff算法复杂度能降到O(n)的原因。
同理,当树的同一个位置遇到前后不同的组件时,也是销毁原组件,把新的组件加上去。这应用了第一个假设,不同的组件一般会产生不同的DOM结构,与其浪费时间去比较不同的DOM结构,还不如完全创建一个新的组件加上去。
2)节点类型相同,但是属性不同:
React会对属性进行重设从而实现节点的转换
3)节点类型相同且属性相同
对于同层节点,若节点本身完全相同(类型相同且属性相同),只是位置不同,则React只需要考虑同层节点的位置变换,不需要进行节点的销毁和重新创建,这就需要用到下面介绍的key属性。
对于不同层的节点,即使节点本身完全相同(类型相同且属性相同),也只能销毁和重新创建。
4)key属性
为列表节点提供唯一的key属性,可以帮助React定位到正确的节点进行比较,从而大幅减少DOM操作的次数,提高性能

Diff 总结

  • 通过diff策略,将算法从O(n^3)简化为O(n)
  • 分层求异,对tree diff进行优化
  • 分组件求异,相同类生成相似树形结构、不同类生成不同树形结构,对component diff进行优化
  • 设置key,对element diff进行优化
  • 尽量保持稳定的DOM结构、避免将最后一个节点移动到列表首部、避免节点数量过大或更新过于频繁

你可能感兴趣的:(react,react)