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

时间:2021-06-02 03:15:49

标签: reactjs

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

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

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

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

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:我采用这种结构的原因是,在我的孩子中,我有一个非常大的表格,并且同一个表格被使用了两次。

2 个答案:

答案 0 :(得分:0)

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

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

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

答案 1 :(得分:0)

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

在我继续之前:注意:

  • this section - 阅读“渲染”和“更新”定义。
    总结:“更新”是执行 FC(功能组件)主体,“渲染”是更新,包括以下效果。
  • 从 effect 中调用 state hook(如 useEffect 或 useLayoutEffect)将导致 React 安排另一个渲染。 see example
  • 从 FC 主体调用状态挂钩将导致 React 安排另一个更新调用。 see example

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

关于您的案例:

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

下单

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

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

如果您很难理解它,我真的建议您阅读我的文章 how-react-hooks-work,其中包含演示这些行为的简单到复杂的示例。