首页 > 解决方案 > 使用 useState 更新深层嵌套状态无法正常工作

问题描述

我按照这个线程中的答案尝试更新我在 React 中深度嵌套的对象。 React:使用 Hooks 为深度嵌套对象设置状态

在那里看起来像魅力的东西,在执行以下操作时会以某种方式打破:

我有一个表,其中填充了来自如下定义的数组中的项目:

const [items, setItems] = useState([
{
  selected: false,
  title: 'Item 1',
  status: 'new'
},
{
  selected: false,
  title: 'Item 2',
  status: 'used'
},
]);

从该列表中选择一个项目时,调用此函数以更新selected具有索引的对象的变量,i如下所示:

const select = (e) => {
  const i = e.target.getAttribute('data-index');
  setItems((prevState) => {
    prevState[i].selected = !prevState[i].selected;
    return [...prevState];
  });
};

这将只工作一次。如果我第二次触发select或在此之后的任何时间以return [...prevState]某种方式继续返回状态不变。(selected永远true存在)。我无法解决这个问题。

items像这样附加到一个组件List

<List
   items={items}
/>

和内部List(缩短的代码):

{items.map((item, i) => {
      return (
        <tr className="list-table-tr">
          {hasSelector ? (
            <td className="list-table-td-selector">
              {item.selected ? (
                <div
                  data-index={i}
                  className="global-selector-selected"
                  onClick={select}
                ></div>
              ) : (
                <div
                  data-index={i}
                  className="global-selector-unselected"
                  onClick={select}
                ></div>
              )}
            </td>
          ) : null}

标签: javascriptreactjsecmascript-6use-state

解决方案


你打破了 React 状态的主要规则之一:你直接修改一个状态对象,而不是制作一个副本。

要正确进行更新,您可以这样做:

const select = (e) => {
    const i = e.target.getAttribute('data-index');
    setItems((prevState) => {
        // Copy the array (your code was doing that)
        const update = [...prevState];
        const item = update[i];
        // Copy the object (your code wasn't doing that) and update its
        // `selected` property
        update[i] = {...item, selected: !item.selected};
        return update;
    });
};

请注意如何复制数组和对象而不仅仅是数组。


推荐阅读