仅在多个子组件已完成运行之后才更新父组件

时间:2019-06-27 05:59:16

标签: javascript reactjs

我有一个Parent react组件,其中有多个通过.map()函数创建的子组件。我正在传递函数addCallback()作为子道具,因此我有一个引用,可以通过父项触发所有子项的handleRun()函数。

我正在尝试将所有子代都在运行时将我的父级组件的状态更新为running = true,并将所有子代都已完成运行时的状态更新为running = false并在父级上呈现该状态。但是状态似乎没有按照我指定的特定顺序更新。

这是我的做法:

let promise1 = this.setState({isRunning:  true},
            () => {
                this.state.childRef.map(x => x())
            });

Promise.all([promise1])
    .then(() => this.setState({isRunning: false}))

这是codesandbox中的全部代码:link

感谢您的帮助,因为我对React(和Javascript)还很陌生。谢谢!

3 个答案:

答案 0 :(得分:2)

原因runSomething不是Promise。你必须改变。

runSomething() {
  return new Promise((resolve, reject) => {
    this.setState({ status: "running" });
     // simulate running something that takes 8s
     setTimeout(() => {
       this.setState({ status: "idle" });
       resolve(true);
     }, 3000);
  });
}

这里的工作沙箱https://codesandbox.io/s/fragrant-cloud-5o2um

答案 1 :(得分:2)

在函数声明中使用异步会自动返回一个Promise,该Promise会围绕您从函数返回的内容进行包装。您的情况是undefined。这就是为什么您当前的代码目前不会引发任何错误的原因。

您将需要一种机制来等待setTimeout。像这样更改runSomething函数将起作用

  async runSomething() {
    this.setState({ status: "running" });

    // simulate running something that takes 8s
    return new Promise(resolve => {
      setTimeout(() => {
        this.setState({ status: "idle" }, resolve);
      }, 3000);
    });
  }

请注意第this.setState({ status: "idle" }, resolve);行。它确保您的诺言不仅在setTimeout之后得到解决,而且在孩子的状态更改为“ idle”之后也得到解决。这是您的子组件已变为“空闲”状态的正确指示。

代码和框:https://codesandbox.io/s/epic-boyd-12hkj

答案 2 :(得分:0)

这是您要实现的沙箱实现。 Sanbox

在这里我已经在父组件中创建了一个状态,该状态将在运行子项时更新。

this.state = {
  callbacks: [],
  components: [
    {
      index: 0, // we don't need this field its just for your info you can just create [true,false] array and index will represent component index.
      status: false
    },
    {
      index: 1,
      status: false
    }
  ]
};

当组件数组中的所有状态均为true时,我们会将parent的空闲状态更新为running。

  getAllRunningStatus() {
    let { components } = this.state;
    let checkAllRunning = components.map(element => element.status);
    if (checkAllRunning.indexOf(false) === -1) { // you can also use !includes(false) 
      return true;
    }
    return false;
  }

内部渲染功能

<h1>Parent {this.getAllRunningStatus() ? "running" : "idle"}</h1>

注意:-我刚刚写了一个粗糙的代码。您可以根据需要对其进行优化。谢谢