React useState 二维数组问题

Issue with React useState 2D array

我遇到了 useState 的奇怪行为。在沙盒 https://codesandbox.io/s/elastic-ellis-gjre7 中,我有 3 个输入字段,如果单击它们会更改值。问题出在历史状态上,我登录控制台。

预期的行为是,只要您单击其中一个框,它就会将所有 3 个框的状态保存在历史数组中,当我们单击另一个时,它会向历史数组添加新的位置。

单击 1 个框时,它可以正常工作 - “历史 1”显示位置,“历史 2”和“历史 3”未定义。

但是当我们点击第二个框时,它开始表现得很奇怪 - 它重写了之前写的“历史 1”,所以现在“历史 1”和“历史 2”的内容是一样的。奇怪,因为我们所做的只是将新值连接到历史数组,但它会覆盖以前的值。

谁能解释一下,为什么会这样?

你应该这样写:

setHistory((prevHistory) => prevHistory.concat({ ...placements }));

说明: 我相信您正在做的是将以前的状态与当前状态合并,根据我的理解,您想联系阵列 - 如果错误请纠正我 -

在第 16 行,newValue[event.value.id] 发生了变异。意思是,在 history.

的每个元素中更新和引用相同的值

要达到预期的行为,解决方案是引用不同的值。这可以通过克隆的方式来实现。

有关实际示例,请参阅 this fork of your sandbox

// Mutation.
newValue[event.target.id].value = "X";

// Cloning.
const targetId = event.target.id
newValue[targetId] = {...newValue[targetId], value: "X"};

你有几处错误。

  1. 您将 item.id 用作 event.target.id,但您正在根据展示位置的数组索引进行更新,最终您将得到无法预料的结果。

  2. 您正在根据展示位置状态更新历史记录,但是当您更新历史记录时,新展示位置可能尚未准备好。

在这里,我们将根据您的项目 ID 而不是索引来更新您的展示位置。然后我们用新的展示位置同时更新历史记录。

  const handleClick = (event) => {
    // .map is commonly used in this type of situation to update the correct object in the array with new value.
    const newplacement = placements.map(item => item.id === parseInt(event.target.id) ? { ...item, value: 'X'} : item )
    
    setPlacements(newplacement);
    setHistory((prevHistory) => [...prevHistory, newplacement]);
  };

my sandbox