4

I'm trying to do some work in JavaScript - I call an async function from an async function, as shown below.

  useEffect(() => {
    (async () => {
      await asyncFunction();
      // do stuff
    })();
  }, []);

asyncFunction looks like this

const asyncFunction = (dispatch) => {
  return async (data) => {
    try {
      const response = await APICall();

      dispatch({ type: "search", payload: response.data });
    }
    // error handling
}

asyncFunction dispatches to a reducer, which returns return { errorMessage: "", data: action.payload };

With my own testing, I've seen that console.log(asyncFunction()) returns a promise, and console.log(await asyncFunction()) returns nothing.

One weird thing I have noticed is when placing console.log statements in each part of the program, the promise from the function call (in the useEffect block) is printed out first, then the data in the reducer from the console.log statement I added right about return { errorMessage: "", data: action.payload };.

So my question is, how do I access this data? I've looked at some other threads on here which recommend using .then, but that was unsuccessful. Is there a way to do it without passing in a callback function (doing so would mean I need to restructure the whole program).

This post is a bit long, so if you have any questions, or need additional parts of my program, please let me know.

  • In `await asyncFunction();` you're not passing your reducer's `dispatch` as an argument. Can you please share the full code of your component, especially the part where you want to use the data? – Bergi Jan 11 '21 at 13:56

3 Answers3

1

You can do the same process without returning the function and directly completing the process in it.

Change the use effect code as follows:

useEffect(() => {
    (async () => {
      await asyncFunction(dispatch);
      // do stuff
    })();
  }, []);
const asyncFunction = async (dispatch, data) => {
    try {
      const response = await APICall();
      dispatch({ type: "search", payload: response.data });
    }
    // error handling
}

Because in the function you mentioned you are dispatching data to reducer and not returning the data. So instead you can just do the processing work there.

In case you want to return some data, you can refer the code below:

Previous Code:

const asyncFunction = (dispatch, data) => {
  return new Promise((resolve, reject) => {
    APICall()
      .then((reponse)=>{
        dispatch({ type: "search", payload: response.data });
        //This will return value to the calling function. This will act as a return statement
        resolve(response);
      })
      .catch((err)=>{
        //This will be executed if there is any error.
        reject(err)
      })
  })

Changed Code (as @Bergi said to avoid Promise constructor anti-pattern):

useEffect(() => {
    let mounted = true;
    APICall()
        .then((response) => {
            if (mounted) {
                dispatch({ type: "search", payload: response.data });
                //do some stuff here
            }
        })
        .catch((err) => {
            //handle error here
        })
    return () => mounted = false;
}, []);

Promises would be the best way to return data from async function.

Darshan Jain
  • 239
  • 5
  • 14
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Jan 11 '21 at 13:56
  • 1
    @Bergi I hope the promise constructor anti pattern is avoided here in the edited response – Darshan Jain Jan 11 '21 at 19:17
1

I could be totally wrong, but I think that you might be running into issues returning the async function, explained here in docs.

Also, it looks like you might be calling asyncFunction (inside your useEffect hook) without a value for dispatch? Here:

  (async () => {
      await asyncFunction();
      // do stuff

I regurgitated a custom hook for API calls following your plan: link to sandbox. Hopefully it can be helpful!

snorp
  • 11
  • 1
0

AsyncFunction is returning a function, not the data that comes from the API call. What you can do, if I understand your problem correctly, is return the response from the call and remove the initial return statement.

CoderLean
  • 232
  • 1
  • 6