componentWillMount中的异步调用在render方法之后完成

时间:2017-04-09 21:40:02

标签: javascript reactjs asynchronous

我正在尝试在componentWillMount方法中对API执行异步调用。实际上我希望在componentWillMount方法之后执行// Method returns first Item in ArrayQueue template <class Item> unsigned ArrayQueue<Item>::getFirst() const { if (this->isEmpty()) { throw EmptyQueueException("getFirst()"); } else { return myArray[myFirst]; } } // Method returns last Item in ArrayQueue template <class Item> unsigned ArrayQueue<Item>::getLast() const { if (this->isEmpty()) { throw EmptyQueueException("getLast()"); } else { return myArray[(myLast - 1 + myCapacity) % myCapacity]; } } 方法,因为我需要将render传递给props方法中的组件。

这是我的代码:

render

我不明白为什么我的render方法似乎不等待异步调用完成并将未定义的道具传递给我的子组件......

我是对的吗?我该怎么做才能解决这个问题?处理这个问题的方法是什么?

2 个答案:

答案 0 :(得分:56)

您可能需要更好地了解javascript异步行为。异步意味着不等待#34;任务将在后台执行,其他代码将继续执行。管理它的一个好方法是在组件上设置状态。例如,当您输入componentDidMount时,将loading州设置为true。然后,当您的异步函数完成时,将该状态设置为false。在render功能中,您可以显示&#34; loading ...&#34;消息或数据。

以下是一些代码,它显示了获取数据异步的简化示例以及如何在React中处理它。在浏览器中打开开发人员工具,查看控制台输出,以更好地了解React生命周期。

编辑:自2018年4月起,代码已更新为使用新的React生命周期建议。总之,我将componentWillMount替换为更安全的componentDidMount

在组件已经挂载之后更新状态似乎效率低下,因为&#39;组件 DID mount&#39;正确暗示。但是,根据official React documentation on componentDidMount

&#34;如果您需要从远程端点加载数据,这是实例化网络请求的好地方。&#34;

&#34;在此方法中调用setState()将触发额外呈现,但它将在浏览器更新屏幕之前发生。这保证即使在这种情况下将render()被调用两次,用户也不会看到中间状态。&#34;

以下是完整的示例代码:

class MyComponent extends React.Component {
  constructor(props) {
    super();

    console.log('This happens 1st.');

    this.state = {
      loading: 'initial',
      data: ''
    };

  }

  loadData() {
    var promise = new Promise((resolve, reject) => { 
      setTimeout(() => {
        console.log('This happens 6th (after 3 seconds).');
        resolve('This is my data.');
      }, 3000);
    });

    console.log('This happens 4th.');

    return promise;
  }

  componentDidMount() {

    console.log('This happens 3rd.');

    this.setState({ loading: 'true' });
    this.loadData()
    .then((data) => {
      console.log('This happens 7th.');
      this.setState({
        data: data,
        loading: 'false'
      });
    });
  }  

  render() {

    if (this.state.loading === 'initial') {
      console.log('This happens 2nd - after the class is constructed. You will not see this element because React is still computing changes to the DOM.');
      return <h2>Intializing...</h2>;
    }


    if (this.state.loading === 'true') {
      console.log('This happens 5th - when waiting for data.');
      return <h2>Loading...</h2>;
    }

    console.log('This happens 8th - after I get data.');
    return (
      <div>
        <p>Got some data!</p>
        <p>{this.state.data}</p>
       </div>
    );
  }
}

ReactDOM.render(
  <MyComponent />,
  document.getElementsByClassName('root')[0]
);

这是working example on CodePen

最后,我认为React维护者Dan Abramov对现代React生命周期的这种形象有助于可视化发生的事情和时间。

enter image description here

请注意,从React 16.4开始,此生命周期图的误差很小:getDerivedStateFromProps现在也在setState以及forceUpdate之后调用。请参阅官方React博客中有关Bugfix for getDerivedStateFromProps

的文章

interactive version of the React lifecycle diagram允许您选择具有最新行为的React版本16.04。确保你检查&#34;显示不太常见的生命周期&#34;选项。

答案 1 :(得分:-2)

上面的答案可能对您尝试做的事情过于矫kill过正。您需要做的就是使compoentDidMount一个异步函数。然后,您可以在返回诺言的函数调用上使用await关键字。

class MyComponent extends React.Component {

  async componentWillMount () {
  
    await myAsyncCall();
    
  }
  
  render () {
    
  }

}