likes
comments
collection
share

关于React中diff算法数据和视图对应问题

作者站长头像
站长
· 阅读数 3

出现的问题

下图是循环出的几个事件Dom,场景是可以对事件进行增加和删除,点击增加则会在循环数组中加多一条数据,每条数据带上一个叉叉的符号可以删除某一条对应的循环数据,但是当删除的时候,会发现删除第二个的时候,第三个事件消失了。

关于React中diff算法数据和视图对应问题

在这个问题上我一度以为是index错误的问题,因为前任开发者写的index下标用的是0、2、3的标识来给每个事件,别问我为什么没有1,我也不清楚,就算是四个事件,也会是0、2、3、4,不明白不清楚不知道。四年前的代码,不敢恭维。

插件查看循环的数据

关于React中diff算法数据和视图对应问题

可以看出每个事件的Dom为ActionCom,让我们来看看这两个ActionCom,第一个是idAction0,第二个是idAction3

关于React中diff算法数据和视图对应问题

因为电脑的原因插件有时候一直用不了,当我用插件查看dom的时候,到这里就发现了问题,第二个明明是删除掉的,在插件中确实只存在了0和3这两个dom

关于React中diff算法数据和视图对应问题 利用的是这部分数据来进行循环出dom元素,这里的freData就是下面代码中的actionSelect,可以看到打印出的循环数组和dom是不对应的,那就是一个很明显的问题,数据和视图不一致

getActionSelect = () => {
    const actionDom = [];
    const actionSelect = this.state.actionSelect;

    for (let item of actionSelect) {
      if (item) {
        // let key = new Date().getTime()
        actionDom.push(
          <ActionCom
            ref={this.myRef}
            events={this.events}
            actionPropOpts={this.userPropOpts}
            userGroupOpts={this.userGroupOpts}
            changeRelation={this.changeRelation}
            actionHandleDelete={this.actionHandleDelete}
            actionHandleAdd={this.actionHandleAdd}
            idAction={item.id}
            len={item.len}
            num={item.num}
            resetData={this.props.loadData}
            actionDateChange={this.actionDateChange}
            actionFullChange={this.actionFullChange}
            changeFullRelation={this.changeFullRelation}
            handleFullDeleteItem={this.handleFullDeleteItem}
            actionFreChange={this.actionFreChange}
            addSelect={this.addSelect}
          />,
        );
      }
    }
    console.log('actionDom', actionDom);
    // let actionDom_ = _.cloneDeep(actionDom)
    return actionDom;
  };

所以就能知道到底是哪里出现了问题,数据和视图的更新没有同步,并且是循环出的数据,很明显算法在循环实现的时候没有准确识别,说到底应该就是没有使用key,reat的diff算法在更新dom的时候没有使用key,会导致不能精确的更新节点的内容

什么是diff算法

React 的 diff 算法大致步骤如下:

  1. 比较两个顶层元素,如果它们的类型不同,React 会销毁旧的树并构建新的树。
  2. 如果两个元素类型相同,则会比较它们的属性,以更新 DOM。
  3. 如果类型相同,但是子元素不同,则 React 会递归比较它们的子元素。

在比较子元素时,React 会使用 keys(如果已提供)来检测哪些子元素保持不变、被移动或被添加或删除。这样可以避免不必要的 DOM 操作。

总的来说,React 的 diff 算法致力于以最高效的方式更新 DOM,使得实际 DOM 操作尽可能地少,从而提高性能和用户体验。

给循环的每个dom加上key

getActionSelect = () => {
    const actionDom = [];
    const actionSelect = this.state.actionSelect;
    for (let item of actionSelect) {
      if (item) {
        // let key = new Date().getTime()
        actionDom.push(
          <ActionCom
            key={item.id}
            ...
          />,
        );
      }
    }
    return actionDom;
  };

再用插件来查看,可以看到已经都加上了key的标识

关于React中diff算法数据和视图对应问题

再看看视图对应的实现效果是怎么样的。

关于React中diff算法数据和视图对应问题

可以看到已经能成功的删除第二个节点,因为有了key的对应,diff算法就知道哪个节点应该复用,哪个节点不应该复用

如果觉得有趣或有收获,请关注我的更新,给个喜欢和分享。您的支持是我写作的最大动力!

往期好文推荐