如果对象引用未更改,useState将接受更新

时间:2019-01-27 14:29:40

标签: reactjs react-hooks

我认为useState需要具有一个新值才能接受更新:

我创建了这个codesandbox来说明我的意思。

我有这样的嵌套数据结构

   const state = {
      name: "parent",
      data: {
        isExpanded: false,
        children: [
          { name: "one", data: { isExpanded: false } },
          { name: "two", data: { isExpanded: false } },
          { name: "three", data: { isExpanded: false } }
        ]
      }
    };

然后,我使用useState来在状态更改时重新渲染:

function App() {
  const [tree, setTree] = useState(state);

  const toggleExpanded = node => {
    node.data.isExpanded = !node.data.isExpanded;

    setTree(tree);
  };

  return (
    <div className="App">
      <h1>IsExpanded</h1>
      {tree.data.children.map(child => (
        <button onClick={() => toggleExpanded(child)}>
          {child.name} - {child.data.isExpanded ? "on" : "off"}
        </button>
      ))}
    </div>
  );
}

每次调用setTree时都会使用相同的引用,并且更新正在进行。

我认为每次都需要一个新的参考文献吗?

我可能丢失了一些东西,但是使用相同的参考文献却没有进行更新。

2 个答案:

答案 0 :(得分:0)

最好具有不可变状态,因为这种方法对React来说是惯用的。但这也适用于改变现有状态。 setTree(tree)触发更新,tree相同或不同都没关系。

在类组件中,setState(sameState)的工作方式与forceUpdate类似,通常不鼓励这样做。

答案 1 :(得分:0)

这是预期的行为。 useState返回的设置器在这方面与非挂接setState相同。任何执行它都会触发重新渲染,并且是否相同的对象引用都没有关系。

如果您刚刚做过:

node.data.isExpanded = !node.data.isExpanded;

不调用setTree,则不会发生视觉更新,因为不会触发重新渲染。

通常建议避免通过更改现有状态对象来进行状态更新,因为它可能导致某些类型的错误(例如,如果您有将先前状态与新状态进行比较的逻辑,则它们似乎总是如果您通过更改现有对象来进行更改,则相同)。而且,这可能导致的细微问题可能会随着将来的React并发模式功能而扩展,但是React不会阻止您这样做。