React: 当项目的顺序改变时,具有唯一`key`的列表项目会被重新渲染。

创建于 2018-07-15  ·  3评论  ·  资料来源: facebook/react

您要请求功能还是报告错误
漏洞

目前的行为是什么?
在渲染每个 item 元素上将key设置为唯一属性的 item 列表时,如果 item 的顺序与之前的渲染相比发生了变化,则索引更改的 item 元素将重新渲染(创建新实例)而不是重新渲染- 使用现有实例(通过键映射)。

例如https://codesandbox.io/s/r5p48kzop
渲染一个列表boxes ,每个盒子都有idtopleftcolor道具。 每750ms我们都会更新boxes数组中所有元素的 ( top , left ) 值。

在更新时,如果元素的顺序没有改变,那么每个框都会动画到它的新位置。 然而,如果我们取消注释第 31 行,它会随机播放这些框,那么只有在之前渲染中保留其位置的元素才会动画到新位置。

您可以在沙箱中观察这种行为。 _shuffle有时会跳到新位置,而_shuffle关闭时它们总是动画。

如果当前的行为是一个错误,请提供重现的步骤,如果可能,请提供问题的最小演示。 将链接粘贴到您的 JSFiddle (https://jsfiddle.net/Luktwrdm/) 或 CodeSandbox (https://codesandbox.io/s/new) 示例如下:
https://codesandbox.io/s/r5p48kzop

什么是预期行为?
不管boxes的顺序如何,所有框元素都应该动画到它们的新位置,因为它们具有独特的key属性设置。

哪些版本的 React 以及哪些浏览器/操作系统受此问题影响?
反应16.3.216.4.1 ,Chrome,MacOS。

最有用的评论

嘿@dhruvparmar372!

这似乎是 DOM 的限制。 为了证明这一点,我创建了这个JSFiddle ,它改变了两个 DOM 节点的顺序,然后应用一个类来触发转换。

事实证明,您可以通过在更改顺序和更新动画属性之间触发回流来解决此问题。

我在您的 CodeSandbox 中添加了一些代码,通过将<Box />更改为类组件并在构造函数中创建唯一 id 来使其在 React 重新创建组件时可见。 如您所见,id 将保持一致: https :

除此之外,我通过将更新拆分为两个setState将回流解决方法应用于您的示例。 第一个会改变顺序,然后我们触发回流,然后改变位置。 这似乎在 Chrome、Firefox、Safari 和 Edge 中运行良好(CodeSandbox 不支持 IE11,因此我无法在该浏览器上进行测试)。

所有3条评论

嘿@dhruvparmar372!

这似乎是 DOM 的限制。 为了证明这一点,我创建了这个JSFiddle ,它改变了两个 DOM 节点的顺序,然后应用一个类来触发转换。

事实证明,您可以通过在更改顺序和更新动画属性之间触发回流来解决此问题。

我在您的 CodeSandbox 中添加了一些代码,通过将<Box />更改为类组件并在构造函数中创建唯一 id 来使其在 React 重新创建组件时可见。 如您所见,id 将保持一致: https :

除此之外,我通过将更新拆分为两个setState将回流解决方法应用于您的示例。 第一个会改变顺序,然后我们触发回流,然后改变位置。 这似乎在 Chrome、Firefox、Safari 和 Edge 中运行良好(CodeSandbox 不支持 IE11,因此我无法在该浏览器上进行测试)。

嘿@philipp-spiess 感谢您澄清问题和解决方法的示例。

嗨,@philipp-spiess

排序列表也有同样的问题😔
不幸的是,您上面的 Codesandbox 示例不再起作用(

下面是一个例子:
https://jsfiddle.net/9odLvbrx/
它通过简单的 CSS 转换对点击项目进行排序。
问题是过渡仅出现在所选项目上,而忽略了其余项目。

我知道如何解决这个问题(在代码中注释),但它只适用于项目数量永远不会改变的列表。 所以如果我想添加或删除项目 - 这些东西变得非常复杂。 在我的示例中,我如何使用您的回流过载解决方案来实现它?

提前致谢! 😊

此页面是否有帮助?
0 / 5 - 0 等级