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

前端 未结 3 615
天命终不由人
天命终不由人 2021-01-21 14:57

I have an issue with the expected result and the actual result. Even though the fetchData() and fetchnumberOfCommits() methods are called from the

相关标签:
3条回答
  • 2021-01-21 15:31

    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>;
      }
    }
    
    0 讨论(0)
  • 2021-01-21 15:50

    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.

    0 讨论(0)
  • 2021-01-21 15:54

    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;
    
    0 讨论(0)
提交回复
热议问题