React.js组件的生命周期,状态行为和JavaScript的异步特性

时间:2018-10-22 03:28:28

标签: javascript ajax reactjs async-await

我对预期结果和实际结果有疑问。即使从fetchData()调用了fetchnumberOfCommits()componentWillMount()方法,该数组也没有数据。但最后,render方法被调用了两次,其中数组已从API获取数据。 我在上述两个方法中都调用setState()方法,其中它调用了render方法。 我的问题是,为什么在调用这两个方法后数组不立即获取数据?数组在什么时候获取数据?

Code example

3 个答案:

答案 0 :(得分:2)

在第一次安装组件时调用render方法,并且在接收到数据并且状态已更改时再次调用render方法。这就是为什么您看到render方法被调用两次的原因。

componentWillMount()在React 16.3中已弃用。您应该使用componentDidMount()来获取数据,并且应该期望组件在获取数据之前至少渲染一次,因此您需要在数据之前渲染null或加载状态被获取。我提供了一个示例,说明如何检查它是否正确加载并显示加载消息。

class App extends React.Component {

  constructor() {
    super();
    this.state = {
      check: true,
      repositories: [],
      commits: [],
    };
  }

  componentDidMount() {
    this.fetchData();
    this.fetchNumberOfCommits();
  }

  fetchData() { /*...*/ }
  fetchNumberOfCommits() { /*...*/ }

  isLoaded() {
    return this.state.respositories.length > 0;
  }

  render() {
    const { repositories } = this.state;

    if(isLoaded) {
      return repositories.map(repo => {
        return (
          <Api
            repo={repo.name}
            createdDay={repo.createdDay} 
          />
        );
      });
    }

    return <h1>Loading repos...</h1>;
  }
}

答案 1 :(得分:0)

如上所述,您应该将其从componentWillMount中删除,因为从16.3开始不推荐使用。应该能够将其放入componentDidMount中,它将为您工作。

答案 2 :(得分:0)

我也从componentWillMount()更改为componentDidMount(),但遇到了同样的问题。原因是JavaScript的异步特性。当您使用诺言时,它不会等到您从API调用中获得结果。它只是将代码按顺序运行,并保持承诺获取数据。这就是即使调用该函数也得到一个空数组的原因。

您可以使用async/await使代码同步,然后它将等待直到您从API调用中获得结果。 如果运行以下代码示例,您将在控制台中看到结果,其中fetchData1()给出了一个空数组,而fetchData2()给出了包含数据的数组。如果您仔细检查一下控制台,您将看到当调用setState()函数render()时触发。

import React, { Component } from 'react';

class App extends Component {
  constructor(){
    console.log('This is from constructor');
    super();     
    this.state={
      repositories:[],
  }  
  }
  componentDidMount(){
    console.log('This is from componentDidMount');
    this.fetchData1();
    this.fetchData2();
  }
  fetchData1(){
        console.log('This is function is using promises');
        fetch('https://api.github.com/users/94ju/repos').then(results => results.json()).then(repositories =>this.setState({ 
          repositories
        })).then( 
          console.log( this.state.repositories),
          console.log(this.state)
        ) 
        console.log('End of using promises')

  }
  async fetchData2(){
    console.log('This is function is using async-await');
    const check =await fetch('https://api.github.com/users/94ju/repos');
    const checkjson =await check.json();
    console.log('Before setState');
    this.setState({ async_repositories: checkjson });
    console.log( this.state.async_repositories);
    console.log(this.state);
    console.log('End of async-await');
}
  render() {
    console.log("Starting render function");
    const repo =this.state;
    console.log(repo);
    console.log('Ending render function');
    return (
      <div>

      </div>
    );

  }
}

export default App;