【问题标题】:Setting index as key in React should break UI but it does not在 React 中将 index 设置为 key 应该会破坏 UI,但它不会
【发布时间】:2021-02-19 12:44:22
【问题描述】:

我有一个小型 React 应用程序,它将图像 URL 字符串数组呈现为 <img> 元素,并在图像 URL 损坏时将其删除。损坏的 URL 可能发生在数组中的任何位置,这意味着它不满足Robin Pokorny's article 中列出的关于何时可以安全地使用数组索引作为 React 键的条件:

  1. 列表和项目是静态的——它们不经过计算,也不 更改 <img> 列表项都可能因错误而被删除
  2. 列表中的项目没有 ID
  3. 列表永远不会重新排序或过滤

理论上,这意味着如果我在创建 JSX 组件时确实尝试使用索引作为键:

render() {
    return (
      <div id="list">
        {this.state.urls.map((url, idx) => (
          // setting array index as the key, an anti-pattern
          <img key={`${idx}`} src={url} onError={this.handleError} />
        ))}
      </div>
    );
  }

然后我的理解是虚拟 DOM 节点将无法正确区分,并且每个列表项的 src 属性将不会正确更新,因为 React 无法识别键索引为 3 的 &lt;img&gt;(例如) 现在有一个新的 src 值,因为索引 2 处的损坏的 URL 被删除。

简而言之,我是否误解了 React 如何在其协调算法中使用密钥?

注意:只是为了确认,我没有在 handleError 函数中改变状态,所以我不认为这是有贡献的:

handleError(e) {
    const url = e.target.src;
    const newUrls = [...this.state.urls];
    newUrls.splice(newUrls.indexOf(url), 1);
    this.setState({ urls: newUrls });
  }

【问题讨论】:

  • 我有一种感觉,很久以前有人说使用index作为key是一种反模式,每个人都坚持它,但没有人知道为什么。只要您不更改映射项的顺序,使用index 就可以了。
  • @kinduser 我也是这么想的,但是在项目列表中间任意删除元素算不算“改变顺序”?
  • 我相信删除映射元素中间的特定项目是一种顺序更改,您可能应该避免index,但我不是 100% 肯定。也许比我更聪明的人可以证实。
  • 是的,这是订单变更。如果您有[A,B,C] 并删除B,则索引1 将代表C 而不是B。因此,您使用相同的键来表示不同的元素。
  • 对于您的特定情况,它工作正常,因为您传递了道具,并且 src 道具已更改,因此 react 确实会成功重新渲染第二个 img。当您的内部组件(例如 img)使用某些状态而不是 prop 时,就会出现问题,因此在 prop 中您将只有键,因此 react 会认为“那里没有任何变化 - 不需要检查”

标签: reactjs


【解决方案1】:

滥用(或不使用)键可以破坏 UI,而且它肯定会使用具有不受 React 管理的状态(例如输入)的 DOM 元素。

但是,对于完全由 React 管理的元素,滥用键只会导致不必要的 DOM 更改;例如,如果你有一个列表 ["cat.jpg", "dog.jpg"] 并且你用列表索引作为键交换两者,React 必须为两个元素设置 srcs;否则它可以在 DOM 中交换节点的顺序而不设置 srcs。

【讨论】:

  • 超级有用的例子来说明更新,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多