react中的diff算法简述

517 阅读3分钟

react中的渲染是先将jsx转化为虚拟dom,随后再将虚拟dom渲染为真实dom,当发生状态更新的时候,就会根据diff算法比对,相同的就直接复用之前的真实dom,发生了改变的则会重新生成真实dom,这里顺带补充一下diff算法比对的最小粒度是一个标签,同时如果这个标签内部有自己的内容,同时还包含其他的标签,如果只是其中的内容发生了变化,但是其中的标签并没有变化,那么只有其中的内容会重新生成真实dom进行渲染,内部的标签则还是使用之前的真实dom。那么具体的比对内容是根据什么呢?答案是根据key,最明显的就是使用map的时候,如果我们使用index作为key,这个也是经常这么用。

image.png 比如我们点击增加一个li标签,如果我们是按着顺序接下来增加了,其实没什么问题,因为新增加的index和之前的各不相同,但如果我们现在增加的是往头部加,那么就会产生效率的问题,react在解析的时候发现index为0的之前的虚拟dom存在,然后新增加的这个li标签与之前的不一样于是就会重新生成真实dom渲染,剩下的也就要依次重新生成,因而最好的方法就是利用一个类似于id那样的属性来作为key,当然如果这个顺序是正常的情况下使用index也是没有什么关系的。
现在我们验证一下react是通过key来执行diff的这个过程,我们在刚刚的li标签中的文本内容之后增加input输入框,并写入内容。

image.png
现在我们要增加一个啊4,那么我们希望的是啊4在最上面,同时输入框中肯定是空白的,那么看一下实际的效果。

image.png
惊奇的发现啊4确实是增加了,但是文本框的内容怎么不对?
可以利用我们上述的diff思路来解释一下这个过程,当我们点击了增加之后,state发生了改变,那么要update,这个时候开始根据key比对,因为我们的key设置的是index,所以我们发现index为0原来是有的,然后进行比较,比较的时候发现,文本内容发生了变化,然后其中的input标签的内容因为是输入的文本,但本身的input标签包括类型都没有产生变化,因而比较之后会认为没有发生变化,就会继续使用真实dom,但万万没有想到刚刚的真实dom文本框中有内容,因而就一并渲染进来了。以下相同,最后的啊3因为index之前没有,所以重新生成渲染了真实dom。
如果是按着顺序添加就没有任何问题

image.png
当然如果换成id作为key,因为id这种一般是后台传递过来的东西,是作为唯一值存储,所以不会产生什么问题