简体   繁体   English

React useState 2D 数组的问题

[英]Issue with React useState 2D array

I am facing strange behavior with useState.我正面临 useState 的奇怪行为。 In the sandbox https://codesandbox.io/s/elastic-ellis-gjre7 I have 3 input fields, that change value if you click on them.在沙箱https://codesandbox.io/s/elastic-ellis-gjre7 中,我有 3 个输入字段,如果单击它们会更改值。 The problem is with history state, that I log in console.问题出在我登录控制台的历史记录 state 上。

Expected behavior is, that as soon as you click on 1 of the boxes, it saves the state of all 3 boxes in history array, when we click another, it adds to history array new placements.预期的行为是,只要您单击其中一个框,它就会将所有 3 个框的 state 保存在历史数组中,当我们单击另一个时,它会在历史数组中添加新的展示位置。

When clicking 1 box, it works correctly - "History 1" shows placement, and "History 2" and "History 3" are undefined.单击 1 框时,它可以正常工作 - “历史 1”显示位置,“历史 2”和“历史 3”未定义。

But when we click 2nd box, it starts to act strange - It rewrites previously written "History 1", so now the content for "History 1" and "History 2" are the same.但是当我们点击第二个框时,它开始变得奇怪——它重写了之前写的“历史1”,所以现在“历史1”和“历史2”的内容是一样的。 Strange, because all we do is concatenate new value to history array, but it overwrites the previous values.奇怪,因为我们所做的只是将新值连接到历史数组,但它会覆盖以前的值。

Can anyone explain, why does it act in such a way?谁能解释一下,为什么它会这样?

You should write it as the following:你应该这样写:

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

Explanation: I believe what you are doing is you're merging the previous state with the current one, from what I understand you want to contact the arrays -correct me if wrong -说明:我相信您正在做的是将以前的 state 与当前的合并,据我了解,您想联系 arrays - 如果错了,请纠正我 -

On line 16, newValue[event.value.id] is getting mutated.在第 16 行, newValue[event.value.id]正在发生变异。 Meaning, the same value is being updated and referenced in each element of history .意思是,在history的每个元素中都在更新和引用相同的值。

To reach the expected behaviour, the solution is to reference different values.为了达到预期的行为,解决方案是引用不同的值。 This can be achieved by way of cloning.这可以通过克隆来实现。

See this fork of your sandbox for a practical example.有关实际示例,请参阅沙箱的这个分支

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

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

You have several things wrong.你有几件事错了。

  1. You are using item.id as event.target.id, but you are updating base on placements' array index, which you will eventually end up with unforseen results.您将 item.id 用作 event.target.id,但您正在根据展示位置的数组索引进行更新,您最终会得到无法预料的结果。

  2. You are updating history base on placements state, but when you are updating the history, the new placements might not be ready yet.您正在根据展示位置 state 更新历史记录,但在更新历史记录时,新展示位置可能尚未准备好。

Here we will update your placements base on your item id instead of index.在这里,我们将根据您的商品 ID 而不是索引来更新您的展示位置。 Then we update the history at the same time with the new placements.然后我们同时使用新的展示位置更新历史记录。

  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 我的沙盒

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM