我认为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
时都会使用相同的引用,并且更新正在进行。
我认为每次都需要一个新的参考文献吗?
我可能丢失了一些东西,但是使用相同的参考文献却没有进行更新。
答案 0 :(得分:0)
最好具有不可变状态,因为这种方法对React来说是惯用的。但这也适用于改变现有状态。 setTree(tree)
触发更新,tree
相同或不同都没关系。
在类组件中,setState(sameState)
的工作方式与forceUpdate
类似,通常不鼓励这样做。
答案 1 :(得分:0)
这是预期的行为。 useState
返回的设置器在这方面与非挂接setState
相同。任何执行它都会触发重新渲染,并且是否相同的对象引用都没有关系。
如果您刚刚做过:
node.data.isExpanded = !node.data.isExpanded;
不调用setTree
,则不会发生视觉更新,因为不会触发重新渲染。
通常建议避免通过更改现有状态对象来进行状态更新,因为它可能导致某些类型的错误(例如,如果您有将先前状态与新状态进行比较的逻辑,则它们似乎总是如果您通过更改现有对象来进行更改,则相同)。而且,这可能导致的细微问题可能会随着将来的React并发模式功能而扩展,但是React不会阻止您这样做。