key可以重复嘛?为什么不使用index做key

先有问题再有答案

  1. diff算法中key有什么用
  2. react或者vue中 key可以重复嘛 重复了会怎样? 为什么?
  3. 为什么不建议使用index作为key?

key有什么用

diff算法中key用于标识当前元素, 目的是实现节点复用, 所以key应该是稳定的、唯一的。

需要注意 节点复用和组件更新的关系

key是节点复用的前提,相同不一定复用,还有层级和类型的限制。不同一定不复用。

组件依赖项(props|state)发生变化 dom就会被更新。

为什么不建议使用index作为key

无论是react还是vue 当index作为key时 不能有效的实现节点复用 导致性能问题。

如图:

我们的期望是实现n1,n2,n3,n4的dom复用 删除n5并新增n6。然而因为使用index作为key所以会复用所有的dom 但是每个组件的内容实际都是不一致的,所以全部dom都需要做更新处理。因此会有性能问题。

key重复会有什么问题

react 示例

javascript 复制代码
import React, { useState } from "react";

export default function MyApp() {
  const [textList, changeTextStr] = useState([1, 2, 3, 4, 4]);

  return (
    <div>
      {textList.map((t) => (
        <div key={t}>{t}</div>
      ))}
      <button
        onClick={() => {
          changeTextStr([5, 6, 7]);
        }}
      >
        change
      </button>
    </div>
  );
}

点击change后

为什么会多一个4?

分析

实际上这是因为react的diff算法导致的。

简单介绍下就是 react在做diff时 需要经过以下步骤

  1. 遍历新旧两个节点相等时 同时下移指针 当遇到两个节点不一致时跳出循环。
  2. 将剩余旧节点的key和对应的节点对象 存储在map中 因为map的key需要唯一 所以相同的key后面的会覆盖前面的 这就导致 实际节点内容为1,2,3,4,4 但是map中存储的只有1,2,3,4 这个4是第二个4.
  3. 然后遍历剩余新节点 如果在map中找到 则节点复用 并标记。
  4. 如果没有找到说明这个节点需要新增
  5. 在遍历map 得到对应的节点 并删除多余的节点 因为map中保留的是key:4 并且是N5节点 所以删除的也是对应的N5节点。

所以最后会导致N4节点被留在了dom树中。

需要注意的以上只是diff算法的简单描述 本文不是讲解diff算法 而是在解决key重复引起的问题。

vue中key重复也会有这个问题嘛?

xml 复制代码
<script setup>
import { ref } from 'vue'

const list = ref([1,2,3,4,4])
const btn = () => {
  list.value = [5,6,7]
}

</script>

<template>
  <div v-for="item in list">{{ item }}</div>
  <div @click="btn">点击</div>
</template>

点击按钮后: 看起来是可以正常显示的 这又是为什么?

分析

与react一样 vue最终的目标也是要做dom复用。所以也需要一个map来标识是否可以复用。只是vue是以新的列表为基础创建一个key&位置的映射表。 key 5 位于新列表第一项 所以是{5:0} 建立完map后 vue会遍历旧节点数组 如果在map中没找到改节点 说明需要删除。 因此vue可以正确的删除所有节点。

相关推荐
yume_sibai1 小时前
Element Plus 数据展示组件完全指南(15个核心组件)
前端·javascript·vue.js
zzz_23682 小时前
个人 AI 记忆如何跨工具复用:用 Markdown、索引和 Skill 搭一个可治理的记忆库
前端·人工智能·react.js·前端框架·agent·agent测评
lee_curry6 小时前
AI Agent 工程师完整学习路线(面向生产级项目与面试)
人工智能·学习·ai·面试·agent
江湖十年6 小时前
在 Go 中使用 dyno 包处理动态对象
后端·面试·go
数智启示录7 小时前
PostgreSQL 内存调优实战(第 12 篇):work_mem 只调大 64 倍,峰值为什么远不止 64 倍
运维·数据库·经验分享·postgresql·面试
刀法如飞9 小时前
《理解道德经》简版第5章:天地不仁,以万物为刍狗
面试·机器人
weixin_4225554210 小时前
el-menu子菜单点击就被激活,恢复之前的激活状态
javascript·vue.js·elementui
wuyk55510 小时前
107.FreeRTOS 链表深度解析:从原理到面试满分答案
c语言·开发语言·数据结构·stm32·单片机·链表·面试
l1m0_10 小时前
智能电动自行车管理后台实战:AI生成页面与React组件化技巧
前端·react.js·ui·ai·设计
坚果的博客11 小时前
认识 CPF-RN:React Native 鸿蒙官方社区与四大核心仓库
react native·react.js·harmonyos