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 . But at the end, the render method is called twice, where the array has got data from the API. I called the setState() method in both the above-mentioned methods where it calls the render method. 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

Answers:

Answer

The render method is called when the component is first mounted and again when your data is received and the state has changed. That's why you're seeing the render method being called twice.

componentWillMount() was deprecated in React 16.3. 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. 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>;
  }
}
Answer

As stated above you should remove it from componentWillMount as that has been deprecated as of 16.3. Should be able to drop it into a componentDidMount and it will work for you.

Answer

I changed from componentWillMount() to componentDidMount() as well, but I got the same problem . Reason for that was the asynchronous nature of JavaScript . When you use the promises it doesn't wait until you get the results from the API call. 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. 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.

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;

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.