错误:不要在键中使用数组索引

IT技术 reactjs npm
2021-04-22 01:00:17

我正在使用索引在列表中生成键。但是,es-lint 会产生相同的错误。React doc还指出,使用项目索引作为键应该作为最后的手段。

const list = children.map((child, index) =>
    <li key={index}> {child} </li>);

我考虑使用react-key-index. npm install react-key-index给出以下错误:

npm ERR! code E404

npm ERR! 404 Not Found: react-key-index@latest

对允许生成唯一密钥的其他软件包有什么建议吗?对react密钥生成器的任何建议表示赞赏!

5个回答

当您使用数组的索引作为键时,React 将进行优化并且不会按预期呈现。在这种情况下会发生什么可以用一个例子来解释。

假设父组件获取一个包含 10 个项目的数组,并根据该数组渲染 10 个组件。假设然后从数组中删除第 5 项。在下一次渲染时,父级将收到一个包含 9 个项目的数组,因此 React 将渲染 9 个组件。这将显示为第 10 个组件被移除,而不是第 5 个,因为 React 无法根据索引区分项目。

因此,始终使用唯一标识符作为从项目数组呈现的组件的键。

您可以使用唯一的子对象的任何字段作为键来生成自己的唯一键。正常情况下,如果可用,可以使用子对象的任何 id 字段。

编辑:如果组件创建和管理自己的状态,例如在不受控制的文本框、计时器等中,您将只能看到上述行为发生。例如,删除输入组件时发生react错误

@lux 也许我无法正确解释。希望这个链接会有所帮助。stackoverflow.com/questions/46477711/...
2021-05-31 01:00:17
我没有按照这个例子 - 你能提供一个重现这个问题的工作例子吗?我经常使用数组,从未遇到过此类问题。
2021-06-04 01:00:17

key={index}每当修改列表时,就会出现使用问题React 不知道哪个项目被添加/删除/重新排序,因为索引是根据数组中项目的顺序在每个渲染上给出的。虽然,通常它呈现得很好,但仍然存在失败的情况。

这是我在构建带有输入标签的列表时遇到的示例。一个列表基于索引呈现,另一个基于 id 呈现。每次在输入中键入任何内容然后删除项目时,都会出现第一个列表的问题。在重新渲染时,React 仍然显示好像该项目仍然存在。这是💯 UI 问题,很难发现和调试。

在此处输入图片说明

    class List extends React.Component {
      constructor() {
        super();
        this.state = {
          listForIndex: [{id: 1},{id: 2}],
          listForId: [{id: 1},{id: 2}]
        }
      }
      renderListByIndex = list => {
        return list.map((item, index) => {
          const { id } = item;
          return (
              <div key={index}>
                <input defaultValue={`Item ${id}`} />
                <button 
                  style={{margin: '5px'}} 
                  onClick={() => this.setState({ listForIndex: list.filter(i => i.id !== id) })}
                 >Remove</button>
              </div>
          )
        })
      }
      renderListById = list => {
        return list.map((item) => {
          const { id } = item;
          return (
              <div key={id}>
                <input defaultValue={`Item ${id}`} />
                <button 
                  style={{margin: '5px'}} 
                  onClick={() => this.setState({ listForId: list.filter(i => i.id !== id) })}
                 >Remove</button>
              </div>
          )
        })
      }
      render() {
        const { listForIndex, listForId } = this.state;
        return (
          <div className='flex-col'>
            <div>
              <strong>key is index</strong>
              {this.renderListByIndex(listForIndex)}
            </div>
            <div>
              <strong>key is id</strong>
              {this.renderListById(listForId)}
            </div>
          </div>
        )
      }
    }

    ReactDOM.render(
      <List />,
      document.getElementById('root')
    );
.flex-col {
  display: flex;
  flex-direction: row;
}

.flex-col > div {
  flex-basis: 50%;
  margin: .5em;
  padding: .5em;
  border: 1px solid #ccc;
 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
    <div id="root">
        <!-- This element's contents will be replaced with your component. -->
    </div>

这就是发生的事情。我在上面的代码中又添加了两个项目。Codesandbox.io/s/vigorous-morning-6xexu?file=/src/App.js 当您从“key is index”列表顶部删除第一个项目时,新创建的 3 个项目数组的键值为 0 , 1, 2. 在删除之前,初始数组键是 0, 1, 2, 3. Reacts 看到键 0, 1, 2(键的数值而不是数组数据)保持不变,因此不需要重新渲染键为 0、1、2 的项目。因此,尽管数组数据已更改,但显示的列表实际上保持不变
2021-05-28 01:00:17
有那么一瞬间我以为我的光标在自己移动
2021-06-10 01:00:17

千万不能使用数组索引钥匙,这是由他们的阵营团队指出,反模式的文档

这是性能和状态管理的问题。第一种情况适用于将某些内容附加到列表顶部的情况。考虑一个例子:

<ul>
  <li>Element1</li>
  <li>Element2</li>
  <li>Element3</li>
</ul>

现在,假设您想将新元素添加到列表的顶部/底部,然后对列表重新排序或排序(甚至最坏的情况 - 在中间添加一些内容)。所有index基于的key策略都会崩溃。index会是在一个时间,这是不是这样,如果对各元素的存在将是一个独特的不同id

代码笔:

试一试,你会发现在某些时候index基于 - 的key策略正在丢失。

当然,在 React 中,你需要为数组的所有元素传入一个唯一的键值。否则,您将在控制台中看到此警告。

Warning: Each child in an array or iterator should have a unique “key” prop.

因此,作为一个懒惰的开发人员,您只需将循环的索引值作为子元素的键值传入。

当索引用作键时,重新排序列表或从列表中添加和删除项目可能会导致组件状态出现问题。如果键是一个索引,重新排序一个项目会改变它。因此,组件状态可能会混淆,并可能将旧键用于不同的组件实例。

使用索引作为键是安全的有哪些例外?

  • 如果您的列表是静态的并且不会更改。
  • 该列表永远不会重新排序。
  • 列表不会被过滤(从列表中添加/删除项目)。
  • 列表中的项目没有 ID。

Key 应该是唯一的,但仅限于它的兄弟姐妹之间。

使用以下库“react-uuid”:https : //www.npmjs.com/package/react-uuid

每次调用 react-uuid 时,它基本上都会创建随机 ID。

import React from 'react'
import uuid from 'react-uuid'

const array = ['one', 'two', 'three']

export const LineItem = item => <li key={uuid()}>{item}</li>

export const List = () => array.map(item => <LineItem item={item} />)

这应该可以解决问题。

这会降低性能,元素在重新渲染时应该具有稳定的键。
2021-06-13 01:00:17
FWIW 我遇到了一个错误,每次更新挂钩运行时它都会生成一个新的 id,这反过来又一遍又一遍地重新呈现相同的列表。
2021-06-18 01:00:17