2

I have a simple react app which pulls data from an API and prints it to the console. I'm using Axios to get the values from API. Here is the API: https://mobile-tha-server-8ba57.firebaseapp.com/walmartproducts/1/20

import React, { Component } from 'react';
import axios from 'axios';

class Products extends Component {
    state = {
        MetaProducts: []
    }
    async componentDidMount(){
        const res = await axios.get('https://mobile-tha-server-8ba57.firebaseapp.com/walmartproducts/1/20')
        this.setState({ MetaProducts: res.data.products});
    }

    render() {
        console.log(this.state.MetaProducts);
        return(
            <div>
                Products
            </div>

        )
    }
}


export default Products;

But Axios, first returns an empty array and then returns the array with data.

console:
Products.js:14 []
Products.js:14 (20) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]

3 Answers 3

3

This is because in React componentDidMount is called after the render method.

Check the React lifecycle methods here https://reactjs.org/docs/react-component.html#mounting.

It is logging the empty array first which is the default state and then whatever was returned by the axios api call.

Sign up to request clarification or add additional context in comments.

Comments

1

This is because of the asynchronous behaviour of the react life cycles . Your render is called before the completion of your axios request and this.state.Metaproducts was never updated inside render as it was already rendered before your request . You can wait for the callback from the axios and then update the state only after that and make sure to render the product after the completion of ajax.

I have added one more state variable init , and set that as true after getting response from server . By default init will be false and then you can show the "loading message " .

Hope it will help you

import React, { Component } from 'react';
import axios from 'axios';

class Products extends Component {
  state = {
    MetaProducts: [],
    init:0,
  }

  async componentDidMount() {
   await axios.get('https://mobile-tha-server-8ba57.firebaseapp.com/walmartproducts/1/20').then(res => {
      this.setState({ MetaProducts: res.data.products, init:1 });
    });
  }

  renderProduct() {
    return <ul>
    {this.state.MetaProducts.map(p =>
      <li>
        {p.productName}
      </li>
    )};
    </ul>;
  }

  render() {
    return this.state.init ? <div>{this.renderProduct()}</div> : <div>loading...</div>;
   }
}



export default Products;

1 Comment

That's really helpful, thank you. I was also trying to figure out how I can map out the objects. And btw, you haven't declared "res"
1

Did you mean empty array on the console? Sure. It will print empty array. You have to take a look at react lifecycle. Render will run first, then the next is componentDidMount. Because you initiate the MetaProducts as an empty arrray, thats why it will print and empty array first.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.