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"};
你有几处错误。
您将 item.id 用作 event.target.id,但您正在根据展示位置的数组索引进行更新,最终您将得到无法预料的结果。
您正在根据展示位置状态更新历史记录,但是当您更新历史记录时,新展示位置可能尚未准备好。
在这里,我们将根据您的项目 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]);
};
我遇到了 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"};
你有几处错误。
您将 item.id 用作 event.target.id,但您正在根据展示位置的数组索引进行更新,最终您将得到无法预料的结果。
您正在根据展示位置状态更新历史记录,但是当您更新历史记录时,新展示位置可能尚未准备好。
在这里,我们将根据您的项目 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]);
};