Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 如果对象引用未更改,useState将接受更新_Reactjs_React Hooks - Fatal编程技术网

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

Reactjs 如果对象引用未更改,useState将接受更新,reactjs,react-hooks,Reactjs,React Hooks,我认为,useState需要有一个新的值才能接受更新: 我创造这个来说明我的意思 我有一个这样的嵌套数据结构 const state = { name: "parent", data: { isExpanded: false, children: [ { name: "one", data: { isExpanded: false } }, { name: "two", data: { isEx

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

我创造这个来说明我的意思

我有一个这样的嵌套数据结构

   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>
  );
}
函数应用程序(){
const[tree,setTree]=useState(state);
const-toggleExpanded=node=>{
node.data.isExpanded=!node.data.isExpanded;
setTree(树);
};
返回(
扩展
{tree.data.children.map(child=>(
toggleExpanded(子项)}>
{child.name}-{child.data.isExpanded?“开”:“关”}
))}
);
}
每次调用
setTree
并进行更新时,我都使用相同的引用

我想每次都需要一个新的参考来实现这一点


我可能遗漏了一些东西,但更新不是使用相同的引用进行的。

最好使用不可变状态,因为这种方法是惯用的反应方法。但这也会改变现有状态
setTree(tree)
触发更新,不管
tree
是相同还是不同


它与类内组件中的
setState(sameste)
的工作方式相同,这类似于
forceUpdate
,通常不鼓励这样做。

这是预期的行为。
useState
返回的setter在这方面与非hook
setState
的工作原理相同。它的任何执行都将触发重新渲染,不管它是否是同一对象引用

如果你刚刚做了:

node.data.isExpanded = !node.data.isExpanded;
如果不调用
setTree
,则不会发生可视更新,因为不会触发重新渲染


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

我认为事情并没有那么简单。我试图解决的bug是一个更复杂的例子,使用嵌套树的d3层次结构,我最终不得不这样做
const newRoot=getHierarchy(cloneDeep(rootNode.data))
或者
useState
返回了相同的对象。@dagda1您在问题中没有提到任何错误/问题。你只是表示这种行为令你惊讶。如果对现有对象进行状态修改,可以肯定
useState
将继续返回相同的对象,但这本身不会导致任何问题。如果将该树作为道具传递给纯组件,那么该纯组件将无法重新渲染(这就是我在回答中提到的bug)。