简体   繁体   中英

Multiple API calls with Promise.all and dispatch an action

I want to call multiple API's and store each response data in an object then I want to dispatch this response object but I'm getting undefined.

Below is the code I tried. May I know where I'm doing wrong?

/* COMPONENT.JSX */
componentDidMount() {
  callApis(this.props.products, this.props.profileId);
}

/* API.JS */
const getContactDetails = (http, profileId) => 
 (http.get(`https://www.fakeurl.com/${profileId}/contact`));

const getProductDetails = (http, profileId) => 
  (http.get(`https://www.fakeurl.com/${profileId}/product`));

const callApis = (products, profileId) => (dispatch) => {

  const payload = new Map();

  products.forEach((product) => {

  const apis = [getContactDetails, getProductDetails];

  apis.map(api => api(http, profileId));

  Promise.all(apis)
      .then((response) => {
          const apiData = {
              contactData: getParsedContactData(response[0]),
              productData: getParsedProductData(response[1])
          };
          if (payload.get(product.token)) {
              payload.get(companion.token).push(apiData);
          } else {
              payload.set(product.token, [apiData]);
          }
      })
      .catch(err => {
          throw ('An error occurred ', err);
      });
   });
   dispatch({ type: FETCH_API_DATA, payload: payload });
}

I expect the dispatch will be called after all API's were resolved, get parsed, and map into the payload object then it should dispatch.

Array.map returns a new Array, which you are discarding

you're calling dispatch before any of the asynchronous code has run

A few minor changes are required

/* API.JS */
const getContactDetails = (http, profileId) => http.get(`https://www.fakeurl.com/${profileId}/contact`);

const getProductDetails = (http, profileId) => http.get(`https://www.fakeurl.com/${profileId}/product`);

const callApis = (products, profileId) => (dispatch) => {
    const payload = new Map();
    // *** 1
    const outerPromises = products.map((product) => {

        const apis = [getContactDetails, getProductDetails];
        // *** 2
        const promises = apis.map(api => api(http, profileId));

        // *** 3
        return Promise.all(promises)
        .then((response) => {
            const apiData = {
                contactData: getParsedContactData(response[0]),
                productData: getParsedProductData(response[1])
            };
            if (payload.get(product.token)) {
                payload.get(companion.token).push(apiData);
            } else {
                payload.set(product.token, [apiData]);
            }
        })
        .catch(err => {
            throw ('An error occurred ', err);
        });
    }));
    // *** 4
    Promise.all(outerPromises)
    .then(() => dispatch({
            type: FETCH_API_DATA,
            payload: payload
        })
    )
    .catch(err => console.log(err));
}
  1. rather than procucts.forEach, use products.map
  2. capture the promises in apis.map to use in Promise.all
  3. return Promise.all so the outer Promises can be waited for
  4. Promise.all on the outer promises, to wait for everything to complete.
const callApis = (products, profileId) => async (dispatch) => { // use async function
  const payload = new Map();
  for (const product of products) {
    const apis = [getContactDetails, getProductDetails];

    apis.map(api => api(http, profileId));

    await Promise.all(apis)  // await all promise done
      .then((response) => {
        const apiData = {
          contactData: getParsedContactData(response[0]),
          productData: getParsedProductData(response[1])
        };
        if (payload.get(product.token)) {
          payload.get(companion.token).push(apiData);
        } else {
          payload.set(product.token, [apiData]);
        }
      })
      .catch(err => {
        throw ('An error occurred ', err);
      });
  }
  dispatch({ type: FETCH_API_DATA, payload: payload }); // dispatch will be executed when all promise done
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM