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

IT技术 javascript ajax reactjs async-await
2021-05-25 01:10:56

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

代码示例

3个回答

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>;
  }
}

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

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

您可以使用async/await 使代码同步,然后它会等待直到您从 API 调用中获得结果。如果您运行以下代码示例,您可以在控制台中看到结果,其中fetchData1()给出了一个空数组,而fetchData2()to 给出了带有数据的数组。此外,如果您仔细检查控制台,您将看到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;