使用数组的索引作为KEY会导致不好的后果

351 阅读3分钟

使用数组的索引作为KEY会导致不良后果

每个应用程序都会以这样或那样的方式使用列表/数组。在React中使用列表时,需要更加谨慎,因为key prop,它被用于数组中的元素。

key prop是DOM中一个元素的标识。所以,它应该是唯一的和静态的,以便区分不同的元素。如果你没有传递 prop,你最终会在控制台看到这个。key

Warning: Each child in a list should have a unique key prop

在这一点上,如果你认为,hey, it's just a warning... ,你在冒险**(请不要**)。因为这可能看起来不会造成严重的问题,相信我,你也不安全。

实现键的方法

用列表实现键有多种方法。

1.数组的索引

索引作为一个键是一种反模式的做法。这可能是摆脱控制台警告的最简单的方法,但这是一把双刃剑。如果没有适当的知识,这种方法可能会出错。

所以,让我们来看看在哪些情况下

  • 索引不能作为键使用

    1. 如果新的元素被添加到开头或中间的某个地方
    2. 如果数组被过滤了
    const App = () => {
      const [counter, setCounter] = useState(1);
      const [list, setList] = useState([
        {
          id: counter,
        },
      ]);
    
      const addToStart = () => {
        const newId = counter + 1;
        setCounter(newId);
        setList((oldArray) => [
          {
            id: newId,
          },
          ...oldArray,
        ]);
      };
    
      const addToEnd = () => {
        const newId = counter + 1;
        setCounter(newId);
        setList((oldArray) => [
          ...oldArray,
          {
            id: newId,
          },
        ]);
      };
    
      return (
        <div className="App">
          <button onClick={addToStart}>Add To Start</button>
          <button onClick={addToEnd}>Add To End</button>
          <table>
            <tr>
              <th>Id</th>
              <th>Item</th>
            </tr>
            {list.map((item, index) => (
              <tr key={index}>
                <td>
                  <label>{item.id}</label>
                </td>
                <td>
                  <input />
                </td>
              </tr>
            ))}
          </table>
        </div>
      );
    };
    

在上面的代码片段中,我们有一个数组,我们可以在数组的开始/结束处添加元素。如果我们把元素添加到数组的末尾,Item 1 将有键0Item 2 将有键1 。然后,如果元素被添加到数组的开始,Item 3 落在上面,但它最终的键是0 而不是2

为了避免这种意外的行为,我们不应该使用数组索引作为键:

{
  list.map((item) => (
    <tr key={item.id}>
      <td>
        <label>{item.id}</label>
      </td>
      <td>
        <input />
      </td>
    </tr>
  ));
}

现在,如果按照上面同样的步骤,如果元素被添加到数组的开始,Item 3 落在上面,并且会有键值2

  • 索引可以作为键使用

    1. 如果新的元素被推到数组的末端(因为将元素推到数组的末端不会影响现有元素的索引)。
    2. 如果该数组是静态的
    3. 如果数组没有被过滤

    在上面的片段中,如果我们只在数组的末端添加元素,我们可以把数组的索引作为键。

    {
      list.map((item, index) => (
        <tr key={index}>
          <td>
            <label>{item.id}</label>
          </td>
          <td>
            <input />
          </td>
        </tr>
      ));
    }
    

这里是资源库的链接,其中,index 被用作key ,反之则用于转换。这个演示显示了使用索引作为键会导致意外的行为。

2.来自数据集的唯一ID

这无疑是最好的方法,因为你可以从提供的数据中获得唯一的ID:

const items = [
  {
    id: 1,
    value: 'Item 1',
  },
  {
    id: 2,
    value: 'Item 2',
  },
  {
    id: 3,
    value: 'Item 3',
  },
];

<div>
  {items.map((item) => {
    return <div key={item.id}>{item.value}</div>;
  })}
</div>;

3.使用包生成唯一的ID

在你没有与列表一起的唯一ID的情况下,最好是在一些包的帮助下生成唯一的键。互联网上有很多软件包可用于生成唯一的键/ID,如react-uuiduuid。我现在要用react-uuid

import uuid from 'react-uuid';

const arrayWithoutIds = ['user 1', 'user 2', 'user 3'];
const arrayWithIds = arrayWithoutIds.map((element) => {
  return {
    id: uuid(),
    value: element,
  };
});

const Component = ({ arrayWithIds }) => {
  return (
    <div>
      {arrayWithIds.map((item) => {
        return <div key={item.id}>{item.value}</div>;
      })}
    </div>
  );
};

这里需要记住的一点是,键应该在创建数据集时或在组件挂载前生成(componentWillMount ),以防止在每次渲染时生成唯一的ID。

4.Math.Random()

不建议使用Math.Random() ,因为它不稳定。因为,我们不能否认有可能产生两次相同的数字。

总结

  • 尝试使用unique id from dataset /generate unique ids using packages 方法来实现密钥。
  • index 作为钥匙可以作为最后的手段来使用。
  • 不要使用Math.Random() 作为键。

学习愉快