如何在保持状态的同时更改组件顺序?

Flu*_*men 5 reactjs react-hooks

设想

我有一个组件,可以根据用户输入以不同的顺序重新呈现子组件。这些子组件具有状态。

问题

当顺序发生变化时,一个子组件的状态最终会出现在另一个子组件中。举个例子,假设在第一次渲染时我按顺序拥有子组件 A 和 B。在下一次渲染中,顺序更改为 B 和 A。A 中的状态现在位于 B 中,反之亦然。

在Code Sandbox中做了一个更简单的例子来说明这种情况。即使在下一次渲染中颠倒过来,该列表仍保持相同的顺序。

我想这与React 在不同组件之间维护状态的方式有关,其中钩子的顺序很重要。

React 应该能够处理这种情况吗?问题出在我的代码中吗?如果是这样,以不同顺序重新渲染组件的正确方法应该是什么?

Dyl*_*ler 2

这与 React 处理虚拟 DOM 中元素的方式有关。

解决方案:添加一个唯一键(不使用索引),它将起作用。

<StatefulComponent param={"Tomato"} key={"Tomato"} />,
<StatefulComponent param={"Potato"} key={"Potato"}/>
Run Code Online (Sandbox Code Playgroud)

为什么会发生这种行为?

默认情况下,如果未指定键,React 将为列表中的每个组件提供一个键,其值与其最初呈现的索引顺序相同 - 这就是导致问题的原因。因为你还没有定义 id,React 会隐式地将你的组件变成这样:

<StatefulComponent param={"Tomato"} key={0} />,
<StatefulComponent param={"Potato"} key={1}/>
Run Code Online (Sandbox Code Playgroud)

在数组之后reverse()

<StatefulComponent param={"Potato"} key={0} />,
<StatefulComponent param={"Tomato"} key={1}/>
Run Code Online (Sandbox Code Playgroud)

您看到意外行为的原因是因为 React 使用键来识别每个元素。因此,如果您在原始渲染后更改数组顺序,然后在每个渲染上应用索引作为 id,react 将获取首先以该索引渲染的元素作为键,并将其放在该位置。通过将键更改为唯一标识符,React 不会将元素混合在一起(因为唯一标识符永远不会相对于其元素发生变化),并且现在可以按照您想要的顺序准确地呈现每个项目。

示例:我们渲染一个列表:

<div id=1>Foo</div> // Id "1" is now bound to this element
<div id=2>Bar</div>
Run Code Online (Sandbox Code Playgroud)

因此,如果您像这样重新排序列表(请注意 id 更改):

<div id=1>Bar</div> // this will be transformed to <div id=1>Foo</div>
<div id=2>Foo</div> // this will be transformed to <div id=2>Bar</div>
Run Code Online (Sandbox Code Playgroud)

然后,react 会将元素转换为它们首先分配给的任何 id - 这就是为什么拥有唯一标识符很重要。

您可以在这里阅读更多信息:https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318