T
TanStack3y ago
quickest-silver

fetch token and refresh token

so the plan is on the Login page, first I call /login then I get refresh token back, then I need to exchange for an accessToken. So I have a AuthProvider, which is wrapped in a higher level of the whole app:
const [auth, setAuth] = useState<string | null>('');
const [auth, setAuth] = useState<string | null>('');
So on my login page:
const refresh = useRefreshToken();

const {isLoading: isSending, mutate: loginEmail} = useMutation(
async () => {
return await loginWithEmail(email, password).then((res) =>
fetchAccessToken(res.token),
);
},
{
onSuccess: (res) => {
setAuth(res)
navigate('/home');
console.log('res', res);
console.log('auth', auth);
// we get the res value here, but auth is never set
},
onError: (err: errTypes | any) => {
..... Error handling code
}
},
},
);
const refresh = useRefreshToken();

const {isLoading: isSending, mutate: loginEmail} = useMutation(
async () => {
return await loginWithEmail(email, password).then((res) =>
fetchAccessToken(res.token),
);
},
{
onSuccess: (res) => {
setAuth(res)
navigate('/home');
console.log('res', res);
console.log('auth', auth);
// we get the res value here, but auth is never set
},
onError: (err: errTypes | any) => {
..... Error handling code
}
},
},
);
So the problem is, after setAuth() is called, auth is never set. How come?
6 Replies
quickest-silver
quickest-silverOP3y ago
@julien This is very similar to the formData, the auth is NEVER set. So onSuccess, we are able to get res, but setState()... some of them are not called, for weird reason. Some worked as expected...
harsh-harlequin
harsh-harlequin3y ago
So in this case, I think it's because refresh() is called right after setAuth() (in the same function). Since setAuth updates a state, the value of auth is only updated at the next render. So when refresh() is called, auth still contains the old value. In this case, I would probably have refresh() accept the new value as a parameter, then you can call refresh(res.refreshToken).
quickest-silver
quickest-silverOP3y ago
Yeah, I later rewrite the part a bit so I chain it, first get refreshToken then use it fetchAccessToken, then set the accessToken as auth value. But the trick thing is it's not set, just like that formData. Ok, I simplified it and now it's new code, but I think it's exactly like the formData now.
harsh-harlequin
harsh-harlequin3y ago
Looks like the same issue:
setAuth(res)
navigate('/home');
console.log('res', res);
console.log('auth', auth);
setAuth(res)
navigate('/home');
console.log('res', res);
console.log('auth', auth);
this reads the state (auth) right after updating it setAuth(res). States updates are asynchonous, auth will only contain the new value (res) at the next render.
harsh-harlequin
harsh-harlequin3y ago
JavaScript Ramblings
Are you logging the state immediately after updating it? Here's why...
Did you ever stumble upon a situation where it seems no matter what you do, your state does not get correctly updated? import React, { useState, useEffect } from 'react' const PokemonList = () => { const [pokemons, setPokemons] = useState([]); useEffect(async () => { const data = await fetch(`https://pokeapi.co/api/v2/pokemon?lim...
xenial-black
xenial-black3y ago
Yeah, state updates aren't reflected immediately. State setters aren't actually asynchronous per se, instead they communicate to React that it needs to re-render the component with this new state value. This new state value won't be immediately reflected whilst you're still executing in the current closure. React needs to call your function component again with the new state value first. Log the value at the top level of the component body instead and see if it actually updates as you'd expect.

Did you find this page helpful?