【问题标题】:Updating deeply nested state with useState not working properly使用 useState 更新深层嵌套状态无法正常工作
【发布时间】:2021-11-15 03:12:12
【问题描述】:

我按照这个线程中的答案尝试更新我在 React 中深度嵌套的对象。 React: Setting State for Deeply Nested Objects w/ Hooks

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

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

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

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

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}

【问题讨论】:

  • 这里必须成为一个很好的欺骗目标。有人有吗?

标签: javascript reactjs ecmascript-6 use-state


【解决方案1】:

你打破了 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;
    });
};

注意both数组对象是如何被复制的,而不仅仅是数组。

【讨论】:

  • 这行得通!我现在想知道,为什么链接问题的答案是公认的,尽管他们也直接直接修改状态。无论如何,非常感谢你让我摆脱了长达 2 小时的头痛 :)
  • 当只需要更新prevState[i] 时,为什么要复制整个状态?
  • 另外select 应该是一个元素,而不是一个数字
  • @smac89 - 因为这就是 React 的工作方式。状态成员本身 (items) 必须更改,React 才能可靠地呈现更改的项目。当您发布该评论时,答案中的select 就是我回答时的问题。 OP 已经改变了它。
  • @Pixell - 不幸的是,接受的答案不正确。它在某些情况下似乎可以工作,因为它正在制作顶级对象的副本,但它需要复制的内容不止于此,否则将无法可靠地工作。我已经 posted an answer there 解释过了。
猜你喜欢
  • 1970-01-01
  • 2020-01-14
  • 2018-11-17
  • 2019-10-17
  • 1970-01-01
  • 1970-01-01
  • 2017-04-15
  • 2016-11-12
相关资源
最近更新 更多