React diff算法目的是为了复用dom节点,减少不必要的DOM重建。diff算法处于React运行流程中的协调阶段,React将新的虚拟DOM树与旧的fiber树进行迭代比较,并执行diff算法生成新的fiber树,在提交阶段挂载到页面DOM树上。
diff算法分为单节点diff和多节点diff。
单节点diff: 单节点就是只有一个新的虚拟DOM,从老fiber树中找到同级的fiber,如果该fiber的type和key与虚拟DOM的type和key都相同,则认为是同一个节点,可以复用,只需要更新操作,用最新的属性代替旧属性。那么剩余的旧fiber删除即可。如果找不到type和key都匹配的fiber,则只能新建fiber,然后删除旧fiber。
多节点diff: 多节点意味着在同一层级中存在多个子节点。多节点diff包含两轮循环,第一轮循环:在新旧节点同位置对比,找到第一个不能复用的节点,然后以最后一个可复用的节点的下标作为第二轮循环中的基准值,然后开始第二轮循环,第一轮循环后会有三种情况:1. 新dom节点遍历完成:删除剩余的旧fiber,diff完成。2. 旧fiber遍历完成,虚拟dom节点还未遍历完成,则逐一为虚拟dom节点创建fiber并插入,diff完成。3. 老节点、新节点都未遍历完成,则需要将剩余的旧fiber放入到map中,如果fiber有key,则将key作为map的key,没有则将index作为map的key,fiber作为map的value,然后开启第二轮循环。
第二轮循环:假设一个场景:有5个新节点1,2,3,4,5。 新节点1、新节点2都已经复用,则从新节点3开始比较,在map中查找key相同,并且type也相同的fiber,找到后复用该fiber,并且基准值lastindex更新为该fiber的下标,同样新节点4也在map中查找,如果找到了fiber,fiber在lastindex的右边,则认为不需要移动,直接复用即可,否则fiber在lastindex的左边,则认为需要移动,打上移动标记。如果新节点遍历完,则第二轮循环结束,删除map中剩余的fiber,整个diff结束。