Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Promise.then is not a function - handling multiple API calls in React

I'm using react-select to auto-complete options in a search bar. The search bar displays the results in one of two categories, depending on which API endpoint it hits.

Right now, it works with data from either one point or the other, but I'm having trouble returning data from both endpoints to react-select's loadOptions parameter.

From this answer about multiple API calls, I decided to use promises to return all the data at once, but I get the error Uncaught TypeError: promise.then is not a function at Async.loadOptions

Here's my code for loadOptions:

const getAsync = (tripId, destinationIndex, input) => {
  if (!input) {
    return { options: [] }
  }

  function getMusement(input) {
    return new Promise(function(resolve, reject) {
      TVApi.musement.autocomplete(input)
        .then((m) => {
          const musementOptions = m.map(musementToOption).slice(0, 4)
          return resolve(musementOptions)
        })
    })
  }

  function getFourSquare(tripId, destinationIndex, input) {
    return new Promise(function(resolve, reject) {
      TVApi.spot.autocomplete(tripId, destinationIndex, input)
        .then((fs) => {
          const fsOptions = fs.map(spotToOption).slice(0, 4)
          return resolve(fsOptions)
        })
    })
  }

  return Promise.all([getMusement(input), getFourSquare(tripId, destinationIndex, input)])
    .then((allData) => {
      const merged = [].concat.apply([], allData)
      console.log(JSON.stringify(merged)) // logs out with correct data
      return {options: merged}
    })
}
like image 727
crash springfield Avatar asked May 11 '17 13:05

crash springfield


People also ask

What is the Promise in API call?

The new promise resolves when all listed promises are resolved, and the array of their results becomes its result. Please note that the order of the resulting array members is the same as in its source promises. Even though the first promise takes the longest time to resolve, it's still first in the array of results.

How many promises can Promise all handle?

all itself as a promise will get resolved once all the ten promises get resolved or any of the ten promises get rejected with an error.


2 Answers

Your problem is that getAsync does not always return a promise, so you could not chain .then(…) to every call. When there is no input, you were returning a plain object - instead you need to return a promise that is resolved with that object:

if (!input) {
   return Promise.resolve({ options: [] });
}
like image 197
Bergi Avatar answered Oct 14 '22 03:10

Bergi


So it turns out the if statement was causing the error:

if (!input) {
  return {options: []}
}

but I have no idea why that would. If someone could explain why, that would be good to know for future issues.

Here's the solution I got following @Bergi's advice avoiding the Promise Constructor antipattern

const loadOptions = (tripId, destinationIndex, input) => {

  function getMusement(input) {
    return TVApi.musement.autocomplete(input)
      .then((m) => {
        const musementOptions = m.map(musementToOption).slice(0, 3)
        return musementOptions
      })
  }

  function getFourSquare(tripId, destinationIndex, input) {
    return TVApi.spot.autocomplete(tripId, destinationIndex, input)
      .then((fs) => {
        const fsOptions = fs.map(fsToOption).slice(0, 2)
        return fsOptions
      })
  }

  return Promise.all([getMusement(input), getFourSquare(tripId, destinationIndex, input)])
    .then((allData) => {
      const merged = [].concat.apply([], allData)
      return {options: merged}
    })
}
like image 29
crash springfield Avatar answered Oct 14 '22 04:10

crash springfield