Home > Back-end >  React: Is useEffect() firing before the response arrives from the function I called?
React: Is useEffect() firing before the response arrives from the function I called?

Time:07-02

Does useEffect fire before the response for data arrives, hence the reason I get undefined immediately first before getting the proper data shortly after?

My logic is

  1. LoginScreen and set token (jwt)
  2. Define isLoggedIn state then conditionally render HomeScreen
  3. OnHomeScreen call getUserDetails() using the provided JWT

HomeScreen:

const {token, userInfo} = useContext(LoginContext)
const [stateUserInfo, setStateUserInfo] = userInfo
const [stateToken, setStateToken] = token

async function getUserDetails() {      
    const data = await axios.get(apiValidate '&JWT=' stateToken)
    setStateUserInfo(data.data.data) //does this line run regardless if the response arrives or not?
}

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

useEffect(() => {
    console.log(stateUserInfo) //returns undefined 1st, then the proper object shortly after
},[stateUserInfo])

I 'fix' my code by doing:

useEffect(() => {
    if(stateUserInfo) { 
        console.log(stateUserInfo) } 
},[stateUserInfo])

This works but I think it's ugly?

On a deeper question, I feel like I'm trying to do "synchronous" logic with async data! Is there a more elegant way to do this? Maybe my logic is flawed?

CodePudding user response:

useEffect will run on initial render as well. That means both of your effects will run the first time, but the second one will run when the stateUserInfo updates as well.

You can fix this by storing a boolean that validates if you're on the initial render or on subsequent ones. This way you can combine both effects into a single one.

Also, for the commented question in your code: YES, it will run regardless of the return of the server. You should add that request in a try catch in case it throws an error, and also check the response in case it is unexpected.


const {token, userInfo} = useContext(LoginContext)
const [stateUserInfo, setStateUserInfo] = userInfo
const [stateToken, setStateToken] = token

// store a boolean to determine if you're on initial render
const afterUpdate = useRef(false)

async function getUserDetails() {      
    const data = await axios.get(apiValidate '&JWT=' stateToken)
    setStateUserInfo(data.data.data) // this line WILL run regardless of the answer of the previous line, so you should validate the response first before assigning it.
}

useEffect(() => {
     if (afterUpdate.current) {
         console.log(stateUserInfo)
     } else {
        afterUpdate.current = true
        getUserDetails()
     }
},[stateUserInfo])
  • Related