1.React的渲染机制
要掌握react的Diff算法我们必须先了解一下其渲染的机制:在每一次的状态或者属性更新的时候,react组件的render方法会进行渲染,返回一个虚拟DOM对象,这个就是react的渲染机制。
2. React的Diff算法
但是这里就有个问题,每次生成新的DOM结构,也还是要转化为真实的DOM,还是会带来大量的真实DOM的操作,会影响程序的执行效率。这时就涉及了react的比较状态变化前后的两个树的Diff算法:在状态变化后通过比较两次虚拟DOM树结构的变化,找出两者的差异部分,再去更新到真实的DOM树上,这样就减少了对DOM的操作,提升了程序效率。
3. 不同情况下Diff算法
1)根节点不同
我们都知道react组件必须由一个根节点包裹,当根节点发生变化,例如:从div变为span或组件之间A换成B时,react会认为新旧两棵树完全不同,不会再继续向下比较,会拆掉整课旧树,整个更新到真实的DOM树上,提一点这时会调用componentWillUnmount函数。
2)根节点相同
如果根节点不变化,只会去更新变化的属性,如下:
<div className=”a” title=”React”></div>
<div className=”b” title=”React”></div>
Diff算法这时回去比较他们的属性变化,也只会去更新className。
3)当根节点是相同的组件类型
调用的是相同的组件的时候,如果状态变化,会使用到周期函数componentWillReceiveProps()和componentWillUpdate(),组件比较的原则是在render执行之后,从根节点开始向下比较进行渲染。比较完差异后再进行渲染。
下面来具体看一下:
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
我们比较一下上下两个树的变化,diff算法从根节点开始进行比较,只会认为添加了一个<li>third</li>,后进行插入渲染。我们再看一下下面这个例子:
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>third</li>
<li>first</li>
<li>second</li>
</ul>
我们观察可以看到<li>third</li>节点提升至第一位,这时比较两树的变化时react就会认为ul下每个节点都发生了变化:<li>first</li>变为<li>third</li>,<li>second</li>变为<li>first</li>,并添加了<li>second</li>,这时的渲染就会消耗过大,效率很低。
React应对这种情况是给节点添加key值,key值的唯一性在渲染时就会自动进行判断,例如上面的两棵树:
<ul>
<li className=”first”>first</li>
<li className=” second”>second</li>
</ul>
<ul>
<li className=” third”>third</li>
<li className=” first”>first</li>
<li className=” second”>second</li>
</ul>
这时候就只会认为只有添加<li className=” third”>third</li>的变化,所以另外有一点我们要注意key值不要用index,因为如果顺序变化,key就会变化,在和之前的key比较,key一样的但是元素却不同了,数据的赋值取值会受到影响,所以不建议使用。
4.小结
react的diff算法,比较新旧两棵虚拟DOM树,极大的减少了对于DOM树的操作,提升了程序的效率。