【发布时间】:2021-02-19 12:44:22
【问题描述】:
我有一个小型 React 应用程序,它将图像 URL 字符串数组呈现为 <img> 元素,并在图像 URL 损坏时将其删除。损坏的 URL 可能发生在数组中的任何位置,这意味着它不满足Robin Pokorny's article 中列出的关于何时可以安全地使用数组索引作为 React 键的条件:
- 列表和项目是静态的——它们不经过计算,也不 更改 <img> 列表项都可能因错误而被删除
- 列表中的项目没有 ID
- 列表永远不会重新排序或过滤
理论上,这意味着如果我在创建 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 的 <img>(例如) 现在有一个新的 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