diff算法是能够更加高效快捷更新页面元素的算法,那如何帮助diff更快呢?
那答案就一定是合理的使用key。
diff
的调用是在reconcileChildren
中的reconcileChildFibers
,当没有可以复用current
fiber
节点时,就会走mountChildFibers
,当有的时候就走reconcileChildFibers
。
而reconcilerChildFibers
的函数中则会针render
函数返回的新的jsx
数据进行判断,它是否是对象,就会判断它的newChild.$$typeof
是否是REACT_ELEMENT_TYPE
,如果是就按单节点处理。 如果不是继续判断是否是REACT_PORTAL_TYPE
或者REACT_LAZY_TYPE
。
继续判断它是否为数组,或者可迭代对象。
而在单节点处理函数reconcileSingleElement
中,会执行如下逻辑:
- 通过
key
,判断上次更新的时候的Fiber
节点是否存在对应的DOM
节点。 如果没有 则直接走创建流程,新生成一个 Fiber 节点,并返回 - 如果有,那么就会继续判断,
DOM
节点是否可以复用?
<!---->
- 如果有,就将上次更新的
Fiber
节点的副本作为本次新生的Fiber
节点并返回
<!---->
- 如果没有,那么就标记
DOM
需要被删除,新生成一个Fiber
节点并返回。
React
是如何判断一个 Fiber
节点是否可以被复用的。
- 第一步:判断
element
的key
和fiber
的key
是否相同
<!---->
- 如果不相同,就会创建新的
Fiber
,并返回
<!---->
- 第二步:如果相同,就判断
element.type
和fiber
的type
是否相同,type
就是他们的类型,比如p
标签就是p,div
标签就是div
.如果type
不相同,那么就会标识删除。
<!---->
- 如果相同,那就可以可以判断可以复用了,返回
existing
。
而在多节点更新的时候,key
的作用则更加重要,React
会通过遍历新旧数据,数组和链表来通过按个判断它们的key
和 type
来决定是否复用。
言而总之,需要合理的使用key
来加快diff
算法的比对和fiber
的复用。
那么如何合理使用key
呢。
其实很简单,只需要每一次设置的值和我们的数据一直就可以了。不要使用数组
的下标,这种key
和数据没有关联,我们的数据发生了更新,结果 React
还指望着复用。