我有一个父组件,它有自己的状态并且也被子组件共享。
在我的子组件中,我有一个表单和数据,我已经创建了一个本地状态。让我们调用这个子组件。
在我的父组件中,有一个单击按钮,我将数据从我孩子的本地状态更新到我父母的状态。这是我通过将一个标志从父级传递给子级来实现的。
我的父母也将同一个孩子渲染两次,最终代码如下:
const parent = () => {
const [parentState, setParentState] = useState(null);
const [submitSignal, setSubmitSignal] = useState(false);
const handleSave = () => {
setSubmitSignal(true);
}
return (
<div>
<div onClick={handleSave}>
Save Data
</div>
<Child
pos={0}
key={0}
parentState={parentState}
submitSignal={submitSignal}
setParentState={setParentState}
/>
<Child
pos={1}
key={1}
parentState={parentState}
submitSignal={submitSignal}
setParentState={setParentState}
/>
</div>
)
}
const Child = (props) => {
const [childState, setChildState] = useState(null);
React.useEffect(() => {
const { pos, submitSignal, parentState, setParentState } = props;
if (submitSignal) {
setParentState(...parentState, ...childState);
}
}, [props.submitSignal])
return (
<div>
// A large form which multiple fields
</div>
)
}
现在这里发生的事情是,一旦我从我的父组件设置 submitSignal 为真,子组件就会同时接收它并尝试更新父组件的状态。这是一种竞争条件情况,即 Child 0 更新数据,但在它甚至在父状态中更新之前 Child 1 也会更新父状态,从而覆盖/删除 Child 0 添加的内容。
请帮我解决这个问题。
P.S:我采用这种结构的原因是,在我的孩子中,我有一个非常大的表格,并且同一个表格被使用了两次。
答案 0 :(得分:0)
你必须使用回调函数,而不是直接设置父状态。这样,您将在覆盖状态时获得更新的先前状态。
if (submitSignal) {
setParentState((pstate)=>{
return {...pstate,...childstate}
});
}
答案 1 :(得分:0)
我明白你为什么感到困惑,这实际上完全按预期工作。
在我继续之前:注意:
有关详细信息,请阅读我的文章 how-react-hooks-work。它将帮助您更好地理解功能组件的生命周期和钩子。
关于您的具体问题:关注 this 代码沙箱,就像您的代码带有一些日志一样。
这里没有任何竞争条件,React 并不关心是否有 1000 个孩子在父级上请求更新(例如通过 setstate)。因为所有更新请求都在同一阶段,所以只会安排一次渲染。
如果您很难理解它,我真的建议您阅读我的文章 how-react-hooks-work,其中包含演示这些行为的简单到复杂的示例。