当使用动态键包裹在 div 中时,React Collapse 过渡不会产生动画

Ada*_*vis 1 animation transition key reactjs

这实在是太奇怪了。我花了很多时间才弄清楚如何解决这个问题。但即使修复了它,我也不知道为什么它会在一种配置中损坏,而在另一种配置中不会损坏。

解释这一点的最佳方法是使用 StackBlitz 现场示例:https ://stackblitz.com/edit/react-collapse-transition-breaks-with-dynamic-key

现场示例详细说明了确切的问题,但概要如下:

  • 这是一个使用 Material UI 的 React 应用程序。
  • 我有一个 <List>,其中填充有 <ListItem> 数组。
  • 这些 <ListItem> 是可单击的。当您单击它们时,它会使用 <Collapse> 转换来公开“子标题”的子 <List>。子标题 <List> 也填充有 <ListItem> 数组。
  • 这就是奇怪的地方:我有一个简单的 <div> ,其中包含“标题” <ListItem>和“子标题”的 <Collapse>-ible <List> 。
  • 因为它们是数组的一部分,所以如果我不向顶级元素(<div>)添加“key”属性,React 就会抱怨。
  • 如果我将动态生成的键值添加到包含 <div> 的键值中,它会以某种方式终止 <Collapse> 元素上的过渡动画。<Collapse> 仍然打开和关闭,但它不会在设定的毫秒数内产生动画效果。它只是打开(立即)或关闭(立即)。
  • 如果我向包含 <div> 的相同元素添加静态键值,则动画效果很好。

为什么动态关键点方法会破坏动画?

Ada*_*vis 5

TLDR:不要在 React 中为数组元素动态生成全局唯一的键。

好吧,经过反复尝试谷歌搜索,我想我终于明白发生了什么事。

当您在 React 中向数组添加项目时,如果您没有向数组中的每个元素添加唯一的“键”,则会引发警告。只要您使用唯一的东西作为每个元素的“键”值,警告就会消失,并且在大多数情况下,React 似乎可以很好地管理数组元素。

当我开始 React 开发时(几年前),我想,“我可以通过使用随机 GUID 生成函数向所有数组元素添加唯一键来轻松解决这个问题。所以我会经常使用如下代码:

let newArray = [];
someMasterArrayOfObjects.forEach(object => {
   if (someConditionIsMet) {
      // SEE HOW CLEVER I THOUGHT I WAS??  USING A RANDOMLY-GENERATED GUID QUIETS THE 
      // UNIQUE-KEY WARNINGS THAT ARE THROWN BY REACT
      newArray.push(
         <div key={createRandomGuid()}>
            {object.title}
         </div>
      );
   }
});
Run Code Online (Sandbox Code Playgroud)

但我错过了 ReactJS 文档中的一个关键词(重点是我的):

键帮助 React 识别哪些项目已更改、添加或删除。应该为数组内的元素提供键,以便为元素提供稳定的标识:

他们在文档中多次使用“稳定”这个词,但它并没有真正深入我的头脑。与大多数开发人员一样,我首先关心的是删除当数组元素缺少唯一键时引发的警告。使用随机生成的 GUID 解决了这个问题。

但 React 使用这些键来确定在状态更改期间应该重新渲染什么。如果每次构建数组中的元素时都随机生成一个新的、全局唯一的键,那么每次设置状态时,React 都会假设所有这些元素都需要从头开始完全重建。

至少,这是低效的。您可能没有注意到小型数组/应用程序中的任何性能影响,但没有理由在每次出于任何原因设置状态时人为地强制重新渲染每个数组元素。您可能没有注意到应用程序中存在任何视觉问题,但这是不好的做法。

在最坏的情况下,它实际上会破坏你的一些功能。就我而言,它破坏了 <Collapse> 过渡动画,因为渲染引擎无法比较一个状态更改与下一个状态更改之间增加的“高度”值 - 因为每次尝试更改该高度时,我都会分配一个全新的,“键”值的全局唯一标识符,React 将其视为一个全新的、完全不同的组件。

当我终于弄清楚要谷歌什么后,我还发现了这个很棒的 JSFiddle:

http://jsfiddle.net/frosas/S4Dju/

请注意,示例中输入的中心行标题为“唯一随机密钥”。当您手动更改这些唯一随机键之一的值时,然后单击“添加项目”,它会破坏您的更改结果,因为它将输入元素重新呈现为全新元素,与他们之前的状态。