最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin1浏览0评论

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}
    })
}

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}
    })
}
Share Improve this question edited May 23, 2017 at 11:47 CommunityBot 11 silver badge asked May 11, 2017 at 13:34 crash springfieldcrash springfield 1,0827 gold badges17 silver badges34 bronze badges 8
  • Avoid the Promise constructor antipattern! – Bergi Commented May 11, 2017 at 13:39
  • does TVApi.musement.autocomplete returns a promise? – Karim Commented May 11, 2017 at 13:40
  • In which line specifically? Are you sure that the TVApi methods do always return promises? – Bergi Commented May 11, 2017 at 13:41
  • @Bergi How would I do this without it? – crash springfield Commented May 11, 2017 at 13:47
  • 1 @crashspringfield You'd just write function getMusement(input) { return TVApi.musement.autocomplete(input).then(m => { … return musementOptions }) } (and the same for getFourSquare) – Bergi Commented May 11, 2017 at 13:49
 |  Show 3 more comments

2 Answers 2

Reset to default 11

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: [] });
}

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}
    })
}
发布评论

评论列表(0)

  1. 暂无评论