useState is accepting updates if the object reference does not change

大兔子大兔子 提交于 2021-02-11 14:00:54

问题


I thought that useState needed to have a new value for it to accept updates:

I have created thiscodesandbox to illustrate what I mean.

I have a nested data structure like this

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

I then use useState to cause rerenders when the state changes:

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>
  );
}

I am using the same reference each time when calling setTree and the updates are happening.

I thought it needed a new reference each time for this to happen?

I might be missing something but is update not happening with the same reference.


回答1:


This is expected behavior. The setter returned by useState works the same in this regard as the non-hook setState. Any execution of it will trigger a re-render and it doesn't matter whether it is the same object reference or not.

If you just did:

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

without calling setTree, then no visual update would occur because a re-render would not be triggered.

It is often recommended to avoid doing state updates by changing the existing state object because it can lead to certain types of bugs (e.g. if you have any logic that compares previous state to the new state, they will appear to always be the same if you do changes by mutating the existing objects). And the possible, subtle issues this could lead to would likely expand with future React concurrent mode features, but React does not prevent you from doing it.




回答2:


It's preferable to have immutable state because this approach is idiomatic to React. But this will work with mutating existing state, too. setTree(tree) triggers an update, it doesn't matter if tree is same or different.

It works the same way with setState(sameState) in class components, which is similar to forceUpdate, which is generally discouraged.



来源:https://stackoverflow.com/questions/54389204/usestate-is-accepting-updates-if-the-object-reference-does-not-change

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!