Home > other >  Call two async functions in a row within React app
Call two async functions in a row within React app

Time:03-15

I have two async functions which reach out to API endpoints (Serverless Framework) - one gets and returns a token, the other gets and returns data using the token.

I'm testing these by using simple buttons, where onClick calls the functions to pull the token and the data, respectively. Click one button to get the token, which is saved to state. Then, once I see the token has been received, I click the other button to get the data. This works without any issues at all.

The problem is when I try calling them sequentially from the React app. I need to call these back-to-back when the user submits a request. I can't seem to make the code wait for the token to arrive before trying to pull the data.

The functions being called in the onClick method of the button:

const tokenBtnOnClick = () =>
{
  const response = getToken().then(x => {
    setToken(x.data.response.token)
  })
}

const dataBtnOnClick = () =>
{
  const response = getData(token, param1, param2, param3).then(x => {
    setData(x.data.response)
  })
}

Async functions:

export async function getToken()
{
    const apiUrl = `${BASE_URL}/handler/getToken`
    const axios = require('axios').default

    let response
    try
    {
        response = await axios.get(apiUrl)
    }
    catch (e)
    {
        console.log(e)
    }

    if (response)
    {
        return response
    }
    else
    {
        return ''
    }
}

export async function getData(token, param1, param2, param3)
{
    const apiUrl = `${BASE_URL}/handler/getData?token=${token}&param1=${param1}&param2=${param2}&param3=${param3}`
    const axios = require('axios').default

    let response
    try
    {
        response = await axios.post(apiUrl)
    }
    catch (e)
    {
        console.log(e)
    }

    if (response)
    {
        return response
    }
    else
    {
        return ''
    }
}

I've tried calling this getBoth() function in a single button's onClick:

async function getBoth()
{
  const tokenResponse = await tokenBtnOnClick().then(x => setToken(x.data.response.token))
  const dataResponse = await dataBtnOnClick().then(x => setData(x.data.response))
}

But even though it's an async function that uses await on both lines, I always get the same TypeError because dataBtnOnClick is called immediately, without actually waiting for the token to come in. When I run this code, tokenBtnOnClick is called, the app crashes due to a TypeError, and then the token comes in and is logged and saved to state.

I've also tried this: (where getData is exactly as above, but now accepts token as a paramter rather than using the state variable)

async function getBoth()
{
  const response = await getToken().then(x => getData(x.data.response.token))
}

index.js?bee7:59 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'then')

How do I get this to actually wait for the token to come in before trying to pull the data?

CodePudding user response:

You are calling setToken and expection token to be updated immediately, but setToken will be asynchronously applied.

Can you useEffect to solve your problem?

useEffect(() => {
  getData(token, param1, param2, param3).then(x => {
    setData(x.data.response)
  })
}, [token])

CodePudding user response:

Try this

    const tokenBtnOnClick = () =>{
       setToken(getToken())
    }

    const dataBtnOnClick = () =>{
       setData(getData(token, param1, param2, param3))
    }

and

const axios = require('axios').default

export async function getToken()
 let apiUrl = `${BASE_URL}/handler/getToken`
{    
    let response = await axios.get(apiUrl)  


        return response.data.token;
        //i don't know exactly what the api returns so it may be diferent

}

export async function getData(token, param1, param2, param3)
{
    let apiUrl = `${BASE_URL}/handler/getData? token=${token}&param1=${param1}&param2=${param2}&param3=${param3}`


    let response = await axios.post(apiUrl)
    return response.data.response;


}

and in your getBoth() just call them because the functions are asynchronous the code will only move forward after them are finished

 getBoth(){
     setToken(getToken())
     setData(getData(token, param1, param2, param3))
 }
  • Related