首页 > 其他分享 >react 学习之从diff children看key的合理使用

react 学习之从diff children看key的合理使用

时间:2024-09-07 12:17:39浏览次数:15  
标签:oldFiber newIdx 复用 react fiber key newChildren diff

大部分优化环节react都自己在内部处理了,但有一种情况也值得开发者注意,那就是列表中key的使用,合理的使用key有助于能精确的找到用于新旧节点复用的老节点。那么我们这里来学习下react 是如何diff children的,从源码的角度看。

用几个案例来描述React diffChild核心流程,react在一次更新中,当发现通过render得到的children如果是一个数组的话,就会调用reconcileChildArray来调和子代fiber,整个对比的流程就是在这个函数中进行的。

diff children流程

第一步:遍历新children,复用oldFiber

function reconcileChildrenArray() {
    // 第一步
    // oldFiber 存在;newIdx应该是一个下标指针
    for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) {
        // 当前循环的旧fiber节点下标大于当前循环小标时
        // nextOldFiber装这个旧fiber
        if (oldFiber.index > newIdx) {
            nextOldFiber = oldFiber;
            oldFiber = null
        } else {
            // 否则,nextOldFiber装它的兄弟节点,也就是下一个需要循环的节点
            nextOldFiber = oldFiber.sibling
        }
        // updateSlot会判断当前的tag和key是否匹配,如果匹配复用老fiber形成新的fiber,如果不匹配,返回Null.
        // returnFiber就是当前oldFiber的父节点,newChildren[newIdx]与oldFiber对应的新的节点,expirationTime过期时间
        const newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], expirationTime)

        if (newFiber === null) break
        // ..一些其他逻辑

        // shouldTrackSideEffects为更新流程
        if(shouldTrackSideEffects){
            // 找到了与新节点对应的fiber,但是不能复用
            // alternate是一个指针,在双缓存树中,workInProgress(内存中构建的树)和current(渲染树)使用alternate指针相互指向
            if(oldFiber && newFiber.alternate === null){
                deleteChild(returnFiber,oldFiber)
            }
        }
    }
}

第二步,统一删除oldfiber

if(newIdx === newChildren.length){
    deleteRemainingChildren(returnFiber,oldFiber);
    return resultingFirstChild
}

这一步其实就是,当第一步遍历完 newIdx === newChildren.length,此时证明所有newChild已经全部被遍历完,那么剩下的oldFiber就没有用了,就统一删除

第三步,统一创建newFiber

if(oldFiber === null){
    for(;newIdx < newChildren.length;newIdx++){
        const newFiber = createChild(returnFiber,newChildren[newIdx],expirationTime)
        // ...
    }
}

第三步适合如下情况,当经历第一步,oldFiber为null,证明oldFiber复用完毕,那么如果还有新的children,说明都是新的元素,只需要调用createChild创建新的fiber

第四步:针对发生移动和更复杂的情况

// 将所有子元素添加到一个键映射中,以便快速查找。
const existingChildren = mapRemainingChildren(returnFiber, oldFiber)
for (; newIdx < newChildren.length; newIdx++) {
    const newFiber = updateFromMap(existingChildren, returnFiber)
    // 从mapRemainingChildren删掉已经复用oldFiber
}

1.mapRemainingChildren返回一个map,map里存放剩余的老的fiber和对应的key(或Index)的映射关系

2.接下来遍历剩下没有处理的Children,通过updateFromMap判断existingChildren中有没有可以复用oldFiber,如果有,那么复用,如果没有,新创建一个newFiber

第五步:删除剩余没有复用的oldFIber

 if (shouldTrackSideEffects) {
      // 检查是否存在未被处理的子节点,如果存在,则将它们添加到删除列表中
      existingChildren.forEach(child => deleteChild(returnFiber, child));
    }

 

关于为什么不能使用Index作为Key

这里我们先来考虑使用math.random作为key会怎么样

如果math.random()作为key,那么每次更新,key都会变,等于key的复用没有用。从而使所有的组件和DOM元素每次都要重新创建。这不仅会造成允许变慢的问题,更有可能导致用户输入的丢失。

同理,使用Index作为key也是一样的,如果选择index作为key,元素发生移动,那么从移动节点开始,后面的fiber都不能做到合理的复用了。

 

标签:oldFiber,newIdx,复用,react,fiber,key,newChildren,diff
From: https://www.cnblogs.com/yaoyu7/p/18401520

相关文章

  • react16之前的虚拟dom数据结构简单简介
    在react16之前的版本中,虚拟dom节点的数据结构看起来大致如下constVitrualDom={type:'div',props:{class:'title'},children:[{type:'span',children:'HelloConardLi'},{type:'ul',......
  • 判断两个map的key 是否完全一致,key完全一致的情况下 判断key对应的值是否一致,一致返回
    你可以通过以下代码来判断两个Map的键是否完全一致,并且键对应的值是否一致:importjava.util.Map;publicclassMapComparer{publicstatic<K,V>booleanareMapsEqual(Map<K,V>map1,Map<K,V>map2){if(map1.size()!=map2.size()){retur......
  • AT_keyence2019_e Connecting Cities 题解
    B算法萌萌题。题解看到完全图求最小生成树,必然是要考虑一下B算法能不能做的。发现这个题的联通块最小值是可以维护的。我们发现。假如我们钦定\(i\)往前面连。那么前面的最小权值必然是一个固定的值。我们一定会连到\(\min(a_j-j\timesD)\)上。由于不能连到自己......
  • AI绘画Stable Diffusion常用插件合集
    宝子们,早上好啊~StableDiffusion常用插件,已经给大家整理好了,自取就好。拥有这些SD常用插件,让您的图像生成和编辑过程更加强大、直观、多样化。以下插件集成了一系列增强功能,覆盖从自动补全提示词到高分辨率图像放大,从双语界面到无边图像浏览,为用户提供了无缝的StableDif......
  • 【AI绘画】Stable Diffusion 喂饭教程来啦!价值上万的模特AI换装方法
    大家好,我是爱绘画的彤姐。在电商领域,最近AI模特换装特别火,结合网上的教程和实战,总结了一个最简单性价比最高的方法。今天我们就一起学起来!!一思路整体的思路其实很简单,分为三步:获取模特服饰的蒙版获取模特的姿势特征图通过图生图局部重绘(上传蒙版)出图在整个过程......
  • 一次了解所有功能!超详细【Stable Diffusion界面】大揭秘!
    对于AI绘画的初学者而言,一看到SD的UI界面肯定是一脸懵,因为有太多陌生词汇,什么大模型、什么提示词、什么什么采样迭代,和传统的画图方式完全不在一个层面上,学习起来就无从下手~今天给大家详细做一个介绍,一起来学吧~SD整合包资源可扫描下方,免费获取01模型设定菜单栏①Sta......
  • Adobe又出黑科技!5秒Ai绘画出图? Stable Diffusion来了!
    据所知2024有两款Ai神器爆火一款是大名鼎鼎的ChatGPT另外一款则是Ai智能绘图软件—StableDiffusion本期重点介绍StableDiffusion尤其最近抖音小红书刷屏的AI人物大部分都是这款软件做的▼StableDiffusion是以文本生成图像的AI工具,也是目前唯一一款能部署在......
  • 界面控件KendoReact中文教程 - 如何创建动态进度条?
    KendoUI致力于新的开发,来满足不断变化的需求。现在我们非常自豪地宣布,通过React框架的KendoUIJavaScript封装来支持ReactJavascript框架。KendoUIforReact能够为客户提供更好的用户体验,并且能够更快地构建更好的应用程序。KendoReact2024Q2新版下载进度条是重要的UI元......
  • 界面控件KendoReact中文教程 - 如何创建动态进度条?
    KendoUI致力于新的开发,来满足不断变化的需求。现在我们非常自豪地宣布,通过React框架的KendoUIJavaScript封装来支持ReactJavascript框架。KendoUIforReact能够为客户提供更好的用户体验,并且能够更快地构建更好的应用程序。KendoReact2024Q2新版下载进度条是重要的UI......
  • React 中的 props 属性传递技巧
    在React开发中,组件之间的通信是非常重要的。props 是React中用于组件间通信的主要机制之一。通过 props,父组件可以向子组件传递数据和回调函数。本文将详细介绍 props 的基本用法、常见问题及如何避免错误,并通过具体的代码示例帮助理解。一、props 的基本用法1.传递基......