简体   繁体   English

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

[英]React.js component life cycle, state behavior and asynchronous nature of JavaScript

I have an issue with the expected result and the actual result. 我对预期结果和实际结果有疑问。 Even though the fetchData() and fetchnumberOfCommits() methods are called from the componentWillMount() still the array has no data . 即使从componentWillMount()调用了fetchData()fetchnumberOfCommits()方法,该数组也没有数据。 But at the end, the render method is called twice, where the array has got data from the API. 但最后,render方法被调用了两次,其中数组已从API获取数据。 I called the setState() method in both the above-mentioned methods where it calls the render method. 我在上述两个方法中都调用setState()方法,其中它调用了render方法。 My problem is why does the array does not get data as soon as the two methods are called? 我的问题是,为什么在调用这两个方法后数组不立即获取数据? and at what point array gets data ? 在什么时候数组获取数据?

Code example 代码示例

The render method is called when the component is first mounted and again when your data is received and the state has changed. 当第一次安装组件时,将调用render方法;当接收到数据且状态已更改时,将再次调用render方法。 That's why you're seeing the render method being called twice. 这就是为什么您看到render方法被调用两次的原因。

componentWillMount() was deprecated in React 16.3. 在React 16.3中不建议使用componentWillMount() You should be using componentDidMount() for fetching data and you should expect that your component will render at least once before your data is fetched, so you'll need to render either null or a loading state before the data is fetched. 您应该使用componentDidMount()来获取数据,并且应该期望组件在获取数据之前至少渲染一次,因此,在获取数据之前,您需要渲染null或加载状态。 I provided an example of how you can check if it was loaded correctly and show a loading message. 我提供了一个示例,说明如何检查它是否正确加载并显示加载消息。

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

As stated above you should remove it from componentWillMount as that has been deprecated as of 16.3. 如上所述,您应该将其从componentWillMount中删除,因为从16.3开始不推荐使用。 Should be able to drop it into a componentDidMount and it will work for you. 应该能够将其放入componentDidMount中,它将为您工作。

I changed from componentWillMount() to componentDidMount() as well, but I got the same problem . 我从改变componentWillMount()componentDidMount()为好,但我得到了同样的问题。 Reason for that was the asynchronous nature of JavaScript . 原因是JavaScript的异步特性。 When you use the promises it doesn't wait until you get the results from the API call. 当您使用诺言时,它不会等到您从API调用中获得结果。 It just run the codes down the order keeping a promise unitl it get data. 它只是将代码按顺序运行,并保持承诺获取数据。 That is the reason that I got an empty array even though the function was called. 这就是即使调用该函数也得到一个空数组的原因。

You can use async/await to make the code synchronized and then it will wait until you get the results from the API call. 您可以使用async/await来使代码同步,然后它将等待直到您从API调用中获得结果。 If you run the following code example you can see the results in the console where fetchData1() gives an empty array and the fetchData2() to gives the array with data .Further if you examine the console well, you will see that when the setState() function is called the render() method triggers. 如果运行以下代码示例,则可以在控制台中看到结果,其中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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM