同时从多个子组件更新父状态

IT技术 reactjs
2021-05-07 17:58:58

我有一个父组件,它有自己的状态并且在子组件之间共享。

在我的子组件中,我有一个表单和数据,我创建了一个本地状态。让我们调用这个子组件。

在我的父组件中,有一个单击按钮,我将数据从我孩子的本地状态更新到我父母的状态。我通过从父级到子级传递一个标志来做到这一点。

此外,我的父母两次渲染同一个孩子,最终代码如下:

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 添加的内容。

这个你能帮我吗。

PS:我采用这种结构的原因是,在我的孩子中,我有一个非常大的表格,并且同一个表格被使用了两次。

2个回答

您必须使用回调函数,而不是直接设置父状态。这样,您将在覆盖状态时获得更新的先前状态。

    if (submitSignal) {
      setParentState((pstate)=>{
         return {...pstate,...childstate}
      });
    }

https://stackoverflow.com/a/68531170/5707801

我明白你为什么感到困惑,这实际上完全按预期工作。

在我继续之前:请注意:

  • 本节中- 阅读“渲染”和“更新”定义。
    总结:'update' 是执行 FC(Fonctional Component)主体,'render' 是包括以下效果的更新。
  • 从 effect 中调用 state hook(如 useEffect 或 useLayoutEffect)将导致 React 安排另一个渲染。看例子
  • 从 FC 主体调用 state hook 将导致 React 安排另一个更新调用。见示例

有关更多详细信息,请阅读我的文章how-react-hooks-work它将帮助您更好地理解功能组件的生命周期和钩子。

关于你的情况:

关于您的具体问题:遵循代码沙箱,就像您的代码带有一些日志一样。

命令

阶段顺序:
  • 家长更新
  • 子更新 * 2
  • 儿童效果*2
  • 父母效应
日志
  • 在安装时,父更新,然后 2 个子更新。然后触发子效果,然后触发父效果。
  • 单击发生 => handleSave 被调用,这将设置状态,在FC body 中,因此 react 将安排另一个更新。
  • 执行更新(记录“父”和“子”*2)。并且 submitSignal 设置为 true。
  • 现在我们处于效果阶段:'submitSignal' 已更新,因此两个孩子都在效果阶段填充 setState(在 Parent 上)=> 安排了另一个父渲染周期。(无关紧要 2 个不同的孩子称为 setState,只有一个渲染将通过react安排)。
  • 父母(和孩子)用更新的值更新。

这里没有任何竞争条件,React 不关心是否有 1000 个孩子在父级上请求更新(例如通过 setstate)。因为所有更新请求都在同一阶段,所以只会安排一次渲染。

如果你很难理解它,我真的建议你阅读我的文章how-react-hooks-work,它有简单到复杂的例子来演示这些行为。