讲起React,当然不能缺少它最重要的特性虚拟Dom,但是很多人都讲不清楚虚拟Dom的内在原理,其实关键点还是这Diff算法。
Diff算法说简单的说就是遍历二叉树,render前和render后的每一个节点做匹配。这里说的节点就是DOM节点但是不是真的DOM节点,而是一个对象类似于
{
tagname:div
className:"a",
style:"width:100px",
onClick:function(){}
children:[
{
tagname:span,
className:"b",
text:"hello",
key:1
},{
tagname:span,
className:"c",
text:"world",
key:2
}
]
}
对应的DOM如下:
<div class="a" style="width:100px" onclick="">
<span class="b"></span>
<span class="c"></span>
</div>
根据二叉树的遍历,从上到下,从左到右遍历,一边遍历,一遍跟旧节点对比。
1.如果一些基本属性如class,style,text变化了(注意不包括id,key,children),则只修改对应DOM的 class,style,innerText
2.如果tagname变化了,那就整个元素删掉,重新creatElement('xx')新的标签。这时候原来的childrem都不会再遍历。
3.如果对象中有key,而且相对于同级元素唯一,那么对于children数组操作的时候,会按key找到元素,修改对应的值。这样的优势是,如果在children中插入一个新的兄弟元素,比如插入头部,它就会判断children[0]的key,跟新插入的是否一致,如果不一致,则创建新元素,然后匹配下一个兄弟元素,并检索是否在旧的childrem是否存在同样id的节点,如果存在,而且被修改过值,则像上面的 1 一样操作。加key优势是不必全量销毁和创建同级DOM。盗一张图类似这样
-
加key,只对同级别元素有效
-
不要变标签,最好能加css隐藏掉
{if isOk == true?<div>1</div>:<span>1</span>}像这样的写法需要经过销毁和创建DOM的过程,如果换成
<div style={{display:isOK?block:none}}>1</div>:<span style={{display:isOK?inline:none}}>1</span>,这样就不会频繁销毁和创建
-
boolean shouldComponentUpdate(object nextProps, object nextState)
如果很有把握这次render可以不进行,就可以用这个方法对比props和state,return false;阻止render进行.