web-dev-qa-db-ja.com

Promise.thenは関数ではありません-React

検索バーのオプションをオートコンプリートするために react-select を使用しています。検索バーには、ヒットしたAPIエンドポイントに応じて、2つのカテゴリのいずれかの結果が表示されます。

現時点では、どちらか一方のデータを処理しますが、両方のエンドポイントからデータを返して反応選択のloadOptionsパラメータに返すのに問題があります。

複数のAPI呼び出しについて この回答 から、Promiseを使用してすべてのデータを一度に返すことにしましたが、エラーUncaught TypeError: promise.then is not a function at Async.loadOptionsが発生します

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

あなたの問題は、getAsyncalwaysを返さないということです。そのため、すべての呼び出しに.then(…)をチェーンすることができませんでした。入力がない場合は、プレーンオブジェクトを返していました。代わりに、そのオブジェクトで解決されるpromiseを返す必要があります。

if (!input) {
   return Promise.resolve({ options: [] });
}
8
Bergi

したがって、ifステートメントがエラーの原因であることがわかります。

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

しかし、なぜそうなるのかはわかりません。誰かが理由を説明できれば、それは将来の問題について知っておくと良いでしょう。

@Bergiのアドバイスに従って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}
    })
}
1