一个React diff算法引起的bug

问题描述

项目中有一个列表渲染,点击搜索按钮后,列表会根据输入的内容进行过滤。但是我用了名字字段作为key,这个名字是可以重复的,点击搜素后,数据并不是想要的结果,多了一些接口外的数据。例如下方代码: 页面默认显示数据1,数据1-重复,执行点击事件后,理论上页面显示一个数据2,但是实际显示的是数据1、数据2

jsx 复制代码
import { useState } from "react";
import styles from "./app.module.css";

function App() {
  const [arr, setArr] = useState([
    {
      label: "数据1",
      value: 1,
    },
    {
      label: "数据1-重复",
      value: 1,
    },
  ]);
  return (
    <div className={styles.card}>
      <button
        onClick={() =>
          setArr([
            {
              label: "数据2",
              value: 2,
            },
          ])
        }
      >
        改变
      </button>
      <div>
        {arr.map((item) => (
          <div key={item.value} className={styles.card_item}>
            {item.label}
          </div>
        ))}
      </div>
    </div>
  );
}
export default App;

问题原因

这个问题主要是因为react diff算法引起的,具体是多节点比较时,发生了问题。react多节点比较主要是reconcileChildrenArray这个函数,会进行2轮遍历,第一轮遍历newChildren,判断对应新旧的key是否一致,下面代码中新的newChildren的一个key是2,old是1,不能复用newFiber为null,就会结束第一轮遍历。

接下来会判断新老节点是否遍历完成,例子中新老都没有遍历完成。然后会把剩余旧节点,以key||index作为Map的key,对应fiber为value。注意这一个操作会把数据1-重复替换数据1。 第二次会遍历剩余新节点,发现在map中没有可以复用的,结束第二轮遍历,然后遍历Map删除旧的剩余节点,比如数据1-重复。

所以最后剩下了数据1,本应该删除的,但是遗留下来了。 vue是没有这个问题的,react为什么不解决这个问题呢?

相关推荐
代码N年归来仍是新手村成员3 小时前
【AWS】Lambda 初识与服务部署
javascript·react.js·ai·node.js·云计算·ai编程·aws
大雷神3 小时前
HarmonyOS APP<玩转React>开源教程三十一:示例项目下载功能
react.js·开源·harmonyos
大鱼前端3 小时前
Veaury:让Vue和React组件在同一应用中共存的神器
前端·vue.js·react.js
五月君_3 小时前
继 React、Vue 之后,Three.js 也有 Skills 了!AI 写 3D 终于不“晕”了
javascript·vue.js·人工智能·react.js·3d
小崽崽13 小时前
如何实现React 19+Vite+TypeScript技术栈告别高薪主播!从零打造 24 小时“AI 销冠”:星云数字人直播间全链路实战
人工智能·react.js·typescript
光影少年6 小时前
Redux Toolkit 用法、解决原生Redux 冗余问题
开发语言·前端·javascript·react.js·中间件·前端框架·ecmascript
whuhewei6 小时前
一道React缓存的题目
javascript·react.js
GISer_Jing1 天前
前端沙箱开源项目推荐(React/Next/Vue优先)
前端·react.js·开源
暗不需求1 天前
React 性能优化秘籍:深入理解 `useMemo` 与 `useCallback`
前端·react.js·面试
向上的车轮1 天前
React 19 快速入门:拥抱服务端组件与新特性的现代化开发
前端·javascript·react.js