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
LoginScreen
and settoken
(jwt)- Define
isLoggedIn
state then conditionally renderHomeScreen
- On
HomeScreen
callgetUserDetails()
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])