Search code examples
javascriptreactjstypescriptasync-awaites6-promise

Dynamically resolve Promise.all responses for each API call and store data


I'm passing right now 3 API calls to Promise.all. For now for each API call i need to create separate Error handler and if data is being return store to it's own object (corresponding to same API object name).

If i pass test4 to Promise.all how can i make it generate it's own error and storing data to state object, instead of my manually adding those values?

I have tried loop the response but getting Object { test3: Promise { "fulfilled" } } and no data.

Code:

import { useCallback, useEffect } from 'react'

const getTest1 = Promise.resolve({ isData: true, isError: false })
const getTest2 = Promise.resolve({ isData: false, isError: true })
const getTest3 = Promise.resolve({ isData: true, isError: false })

export const PromiseAll = () => {
  const getInitialData = useCallback(async () => {
    try {
      const res = await Promise.all([{ test1: getTest1 }, { test2: getTest2 }, { test3: getTest3 }])

      for (let i = 0; i < res.length; i++) {
        const el = res[i]
        console.log('🚀 ~ el', el)
      }

      const test1 = await res[0].test1
      const test2 = await res[1].test2
      const test3 = await res[2].test3

      test1.isError && console.log('Error in test1', test1.isError)
      test2.isError && console.log('Error in test2', test2.isError)
      test3.isError && console.log('Error in test3', test3.isError)

      const state = {
        test1: test1.isData,
        test2: test2.isData,
        test3: test3.isData,
      }
      console.log('🚀 ~ state', state)
    } catch (error) {
      console.log('🚀 ~ Error', error)
    }
  }, [])

  useEffect(() => {
    getInitialData()
  }, [getInitialData])

  return <div>PromiseAll</div>
}

Example here with console.log Object { test3: Promise { "fulfilled" } } in loop https://codesandbox.io/s/romantic-mendel-xm5jk9?file=/src/App.tsx


Solution

  • Sounds like you want something like

    async function awaitNamedPromises(nameToPromise) {
      const namesAndPromises = Object.entries(nameToPromise);
      const promises = namesAndPromises.map(([, promise]) => promise);
      const results = await Promise.all(promises);
      return Object.fromEntries(namesAndPromises.map(([name, promise], index) => [name, results[index]]));
    }
    
    const results = await awaitNamedPromises({
      test1: Promise.resolve('hello'),
      test2: Promise.resolve('world'),
      test3: Promise.resolve('bye'),
    });
    
    console.log(results);
    

    This prints out

    { test1: 'hello', test2: 'world', test3: 'bye' }