Axios API call returning Promise object instead of result?

Question

Before I start, let me say that I'm new to Javascript and very new to axios API calls, so I'm probably making a rookie mistake...

I have this function getObjects() that's meant to map over an array and return the data from an Axios API call. The API call and map function are both working, but I'm getting a Promise object instead of the data I'm trying to get.

I figure this is because the data is returned before there's enough time to actually get it, but not sure how to fix? I tried a .setTimeout(), but that didn't seem to work.

  getObjects() {
    let newsItems = this.state.arrayofids.map((index) => {
      let resultOfIndex = axios.get(`https:\/\/hacker-news.firebaseio.com/v0/item/${index}.json`).then((res) => {
          let data = res.data;
          //console.log(data.by); // this prints the correct byline, but
                              // all the bylines are printed after
                              // the console.log below...
          if (!data.hasOwnProperty('text')) return data;
        }); /// end of axios request
  return resultOfIndex;
    }); /// end of map
    /// ideally this would end in an array of response objects but instead i'm getting an array of promises...
    console.log(newsItems);
  }

(The extra escape characters are for my text editor's benefit.)

Here's a link to a codepen with the issue - open up the console to see the problem. It's a React project but I don't think any of the React stuff is the issue. EDIT: Codepen is link to working solution using axios.all as suggested below

Thanks!

EDIT: Here is my working solution.

getObjects() {
  let axiosArr = [];
  axios.all(this.state.arrayofids.map((id) => {
      return axios.get(`https:\/\/hacker-news.firebaseio.com/v0/item/${id}.json`)
    })).then((res) => {
      for (let i = 0; i < this.state.arrayofids.length; i++) {
        axiosArr.push(<li key={i} data-url={res[i].data.url} onClick={(e) => this.displayTheNews(e)}>{res[i].data.title}</li>);
      }
      if (axiosArr.length == this.state.arrayofids.length) {
        this.setState({arrayofdata: axiosArr});
        console.log('state is set!');
      }
    })
 }

Show source
| javascript   | reactjs   | axios   2017-01-07 17:01 2 Answers

Answers ( 2 )

  1. 2017-01-07 18:01

    axios.all function should be more appropriate to your current scenario.

  2. 2017-01-07 18:01

    Your console.log is executing immediately, rather than waiting for the requests to finish, because they are not synchronous. You have to wait for all the responses before you console.log.

    OPTION 1 (the hard way): replace your console.log with

    newsItems.forEach((promise, index) => {
      promise.then((object)=>{
        newsItems[index] = object
        if (index+1 == newsItems.length) {
          console.log(newsItems)
        }
      })
    })
    


    OPTION 2 (the better way): using axios.all

      getObjects() {
        axios.all(this.state.arrayofids.map((id) => {
          return axios.get(`https:\/\/hacker-news.firebaseio.com/v0/item/${id}.json`)
        })).then((res) => {
          console.log(res)
        })
      }
    

    by the way, I would definitely reccommend changing

    this.state.arrayofids.map((index) => {
          let resultOfIndex = axios.get(`https:\/\/hacker-news.firebaseio.com/v0/item/${index}.json`)...
    

    to be called id instead of index

◀ Go back