简体   繁体   中英

How do I chain async methods inside React useEffect() hook

I am building an e-commerce site with ReactJS and Commerce.js. I have a checkout context provider which is responsible for storing all state and functionality related to the checkout and order data. Below is the basic shape of the checkout state being stored in the context:

const initialState = {
  checkout_token: {
    id: "123456789"
  },
  order_data: {
    fulfillment: {
      shipping_options: [],
      shipping_countries: {},
      shipping_subdivisions: {},
      shipping_option: "",
    },
  }
}

I need to update the fulfillment section of my checkout data. This requires an API request to commerce.js using the checkout_token.id chained with a method call that updates the relevant part of checkout state. Here is one of the 3 methods I use to do this. You can assume the dispatch method works:

const setShippingCountries = (tokenId) => {
    commerce.services
      .localeListShippingCountries(tokenId)
      .then((countries) => {
        dispatch({
          type: ACTIONS.SET_SHIPPING_COUNTRIES,
          countries,
        });
      })
  };

Anytime that the checkout token is changed, I need to update the fulfillment data. I tried doing this with the following useEffect() hook. Note that isMounted is a ref used to stop the effect on mount:

useEffect(() => {
    if (isMounted.current && Object.keys(state.checkout_token).length > 0) {
      setShippingCountries(state.checkout_token.id);
      setSubdivisions(state.order_data.fulfillment.shipping_countries[0]);
      setShippingOptions(state...shipping_countries[0], 
        state...shipping_subdivisions[0]); //Forgive my abbreviation :)
    } else {
      isMounted.current = true; 
    }
  }, [state.checkout_token.id]);

Here is my error: TypeError: Cannot read properties of null (reading 'id')

This is caused because each method references data that was set in the line before. But the data is not updated when I reach the next line. I have tried turning them into Promises and chaining them but I was unable to get it right. I also tried using async...await but couldn't figure that out either. What is the best way to change these methods so that they are called synchronously?

async await version would look like this

 useEffect(() => {
        const f = async () => {
            await setShippingCountries(state.checkout_token.id);
            await setSubdivisions(state.order_data.fulfillment.shipping_countries[0]);
            await setShippingOptions(state.shipping_countries[0]);
        }
        if (isMounted.current && Object.keys(state.checkout_token).length > 0) {
            f()
        } else {
            isMounted.current = true;
        }
    }, [state.checkout_token.id]);

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