componentWillMount中的异步调用在render方法之后完成 [英] Asynchronous call in componentWillMount finishes after render method

查看:2270
本文介绍了componentWillMount中的异步调用在render方法之后完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在componentWillMount方法中对API执行异步调用。实际上我想在componentWillMount方法之后执行 render 方法,因为我需要将 props 传递给我的组件渲染方法。

I am trying to perform an asynchronous call to an API in the componentWillMount method. Indeed I would like the render method to executed after the componentWillMount method as I need to pass props to the component in my render method.

这是我的代码:

class TennisSearchResultsContainer extends React.Component {
  componentWillMount () {
    // TODO: Build markers for the map
    // TODO: Check courtsResults object and database for tennis court
    this.courtsMarkers = this.props.courtsResults.map((court) => {
      return new google.maps.Marker({
        position: new google.maps.LatLng(JSON.parse(court.LOC).coordinates[1], JSON.parse(court.LOC).coordinates[0]),
        title: court.NAME,
        animation: google.maps.Animation.DROP
      });
    });
  }
  render () {
    return <TennisSearchResults criterias={this.props.criterias} courtsMarkers={this.courtsMarkers} />;
  }
}

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

I don't understand then why my render method seems to do not wait for the asynchronous call to finish and pass undefined props to my child component...

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

Am I right? And what should I do to fix that? What is the way to handle this?

推荐答案

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

You might need to understand javascript async behavior better. Async means "don't wait". That the task will happen in the background and other code will continue to execute. A good way to manage this is to set state on your component. For example, when you enter componentDidMount set a loading state to true. Then when your async function completes, set that state to false. In your render function you can then either display a "loading..." message or the data.

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

Here is some code that shows a simplified example of fetching data async and how you could handle that in React. Open the developer tools in your browser and look at the console output to understand the React lifecycle better.

编辑:代码已更新为使用新的React生命周期建议总之,我用更安全的 componentDidMount 替换了 componentWillMount

Code has been updated to use the new React Lifecycle recommendations as of April 2018. In summary, I replaced componentWillMount with the safer componentDidMount.

在组件已经挂载之后更新状态似乎效率低下,因为'component DID mount'正确暗示。但是,根据有关componentDidMount的官方React文档

It might seem inefficient to update the state after the component has already mounted, as 'componentDIDmount' correctly implies. However, per the official React documentation on componentDidMount:

如果你需要从远程端点加载数据,这是一个实例化网络请求的好地方。

"If you need to load data from a remote endpoint, this is a good place to instantiate the network request."

呼叫<此方法中的code> setState()将触发额外的渲染,但它会在浏览器更新屏幕之前发生。这可以保证即使 render()在这种情况下,将被调用两次,用户将看不到中间状态。

"Calling setState() in this method will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state."

以下是完整的示例代码:

Here's the complete example code:

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]
);

这是 CodePen上的工作示例

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

Finally, I think this image of the modern React lifecycle by React maintainer Dan Abramov is helpful in visualizing what happens and when.

< img src =https://i.stack.imgur.com/HZhwN.jpgalt =在此输入图像说明>

注意从React 16.4开始,这个生命周期图有一个小的不准确性: getDerivedStateFromProps 现在也在 setState 之后被调用,以及 forceUpdate 。请参阅官方React博客中有关 getDerivedStateFromProps的修正错误

NOTE that as of of React 16.4, this lifecycle diagram has a small inaccuracy: getDerivedStateFromProps is now also called after setState as well as forceUpdate. See this article from the official React blog about the Bugfix for getDerivedStateFromProps

React生命周期图的交互式版本允许您选择具有最新行为的React版本16.04。确保选中显示不太常见的生命周期选项。

This interactive version of the React lifecycle diagram allows you to select React version 16.04 with the latest behavior. Make sure you check the "Show less common lifecycles" option.

这篇关于componentWillMount中的异步调用在render方法之后完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆