React之旅-05 List Key

每个React的初学者,在调试程序时,都会遇到这样的警告:**Warning: Each child in a list should have a unique "key" prop.**如下面的代码:

TypeScript 复制代码
const list = ['Learn React', 'Learn GraphQL'];

const ListWithoutKey = () => (
  <div>
    <ul>
      {list.map((item) => (
        <li>{item}</li>
      ))}
    </ul>
  </div>
);

这个警告提示我们,需要为列表中的每个元素添加 key 属性。如下面的代码:

TypeScript 复制代码
const ListWithoutKey = () => (
  <div>
    <ul>
      {list.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  </div>
);

使用上面的代码调试时,之前的警告会消失,但其实在其背后,有一个隐式的 bug。当你对列表进行重新排序时,特别是当你添加了非受控的元素,问题就会发生。

如果你的代码如下:

TypeScript 复制代码
const initialList = ['Learn React', 'Learn GraphQL'];

const ListWithUnstableIndex = () => {
  const [list, setList] = React.useState(initialList);

  const handleClick = event => {
    setList(list.slice().reverse());
  };

  return (
    <div>
      <ul>
        {list.map((item, index) => (
          <li key={index}>
            <label>
              {item}
            </label>
          </li>
        ))}
      </ul>

      <button type="button" onClick={handleClick}>
        Reverse List
      </button>
    </div>
  );
};

运行你的代码,点击按钮对列表进行重新排序,看样子,一切正常。

可是当你添加了不受控的元素时,假如你的代码如下:

TypeScript 复制代码
const initialList = ['Learn React', 'Learn GraphQL'];

const ListWithUnstableIndex = () => {
  const [list, setList] = React.useState(initialList);

  const handleClick = event => {
    setList(list.slice().reverse());
  };

  return (
    <div>
      <ul>
        {list.map((item, index) => (
          <li key={index}>
            <label>
              <input type="checkbox" />
              {item}
            </label>
          </li>
        ))}
      </ul>

      <button type="button" onClick={handleClick}>
        Reverse List
      </button>
    </div>
  );
};

在上述的代码中,checkbox 是非受控元素,当你运行上述的代码时,运行的结果,可能和你相像的不太一致。

TypeScript 复制代码
// 列表最初的样子

[x] Learn React
[ ] Learn GraphQL

// 点击按钮,列表重新排序后的样子

[x] Learn GraphQL
[ ] Learn React

这种结果显然不是你想要的,那这背后终究发生了什么呢?

TypeScript 复制代码
// 列表当初的样子

[x] Learn React (index = 1)
[ ] Learn GraphQL (index = 2)

// 点击按钮,列表重新排序后的样子

[x] Learn GraphQL (index = 1)
[ ] Learn React (index = 2)

那如何解决这个问题呢,办法当然有,这次,我们使用了相当稳定的元素作为 key 属性。代码如下:

TypeScript 复制代码
const initialList = [
  { id: 'a', name: 'Learn React' },
  { id: 'b', name: 'Learn GraphQL' },
];

const ListWithStableIndex = () => {
  const [list, setList] = React.useState(initialList);

  const handleClick = event => {
    setList(list.slice().reverse());
  };

  return (
    <div>
      <ul>
        {list.map(item => (
          <li key={item.id}>
            <label>
              <input type="checkbox" />
              {item.name}
            </label>
          </li>
        ))}
      </ul>

      <button type="button" onClick={handleClick}>
        Reverse List
      </button>
    </div>
  );
};

点击按钮,列表重新排序后,背后发生了变化。

TypeScript 复制代码
// 列表最初的样子
[x] Learn React (id = a)
[ ] Learn GraphQL (id = b)

// 点击按钮,列表重新排序后的样子

[ ] Learn GraphQL (id = b)
[x] Learn React (id = a)

在这里,我们使用了 id 作为 key 属性,当然,你也可以使用列表中的其他元素,但前提是这个元素是不可改变的唯一值。

不管怎样,仍然值得注意的是,只要你的列表保持的顺序或大小没有改变,使用索引是可以的。然后,列表中每个项目的位置不会改变------它与索引一样稳定------因此使用索引是可以的。

原文链接:Why do we need a React List Key

相关推荐
李游Leo29 分钟前
HarmonyOS 7 ArkTS + ohpm:三方 JS 库副作用隔离与 API 26 升级回归【鸿蒙心迹】
javascript·回归·harmonyos
你挚爱的强哥34 分钟前
【sgKeyboard】自定义组件:虚拟键盘
前端·javascript·计算机外设
锅里游的鱼吖40 分钟前
echarts自定义折线图
前端·javascript·数据库
hunteritself1 小时前
卷卷卷!GPT-6 Sol、Luna 正式发布,OpenAI 开始卷价格了
大数据·前端·人工智能·深度学习·transformer
何何____1 小时前
Vue 全局事件总线详解
前端·javascript·vue.js
涉密IT资质笔记2 小时前
涉密人员脱密期管理规范:期限分级模型、就业限制边界与违规认定标准
java·服务器·前端·网络·数据库
u0111026752 小时前
工具页案例图如何编写 alt让图片说明与处理场景对应
java·前端·javascript·图像处理·人工智能·算法·ai作画
事圆则缓2 小时前
Flutter 状态管理框架对比(五):GetX 的响应式、依赖注册与生命周期
前端·javascript·flutter
广州智造3 小时前
Radioss复合材料使用的单元属性
前端·设计·cad·建模·cae·radioss
ss2733 小时前
AI全栈实战 | 2.1-03 JavaScript 核心:单线程+事件循环为什么不等同于多线程,原型链 vs Java 继承
java·开发语言·javascript