T
TanStack3y ago
manual-pink

strange behavior on token

I have a token, that I put in localStorage, then I have this below in a global context, in authProvider
const [accessToken, setAccessToken] = useState<string | null>(
localStorage.getItem(ACCESS_TOKEN) ?? null,
);
const [accessToken, setAccessToken] = useState<string | null>(
localStorage.getItem(ACCESS_TOKEN) ?? null,
);
Then after login, if people check remember me, we put that in localStorage, otherwise we just setAccessToken(token) so it's stored in global state, so we can have
const {accessToken} = useAuth()
const {accessToken} = useAuth()
And in this component I have console.log and see that we definitely have the token, it's not null or undefined. However, in my useQuery it will result in some data fetching error. But if I wrote something extra such as
const token = localStorage.getItem(ACCESS_TOKEN)?? accessToken;
const token = localStorage.getItem(ACCESS_TOKEN)?? accessToken;
then use this token, instead of accessToken directly from useAuth, I did not have errors. Component B:
const {accessToken} = useAuth() as AuthContextType;

// have to add a line below to make it work but it doesn't make sense to me if I already do it in useAuth
const token = localStorage.getItem(ACCESS_TOKEN) ?? accessToken;

// fetch data
const {isLoading: isLoadingEmail} = useQuery(
['emailData', token],
async () => {
return await axiosClient.get(ACCOUNT_EMAIL_URL, {
params: {
token,
},
});
},
{
onSuccess: (res) => {
setEmail(res.data.email);
},
onError: (err) => {
console.error(err);
setEmailErr('error loading data');
},
},
);
const {accessToken} = useAuth() as AuthContextType;

// have to add a line below to make it work but it doesn't make sense to me if I already do it in useAuth
const token = localStorage.getItem(ACCESS_TOKEN) ?? accessToken;

// fetch data
const {isLoading: isLoadingEmail} = useQuery(
['emailData', token],
async () => {
return await axiosClient.get(ACCOUNT_EMAIL_URL, {
params: {
token,
},
});
},
{
onSuccess: (res) => {
setEmail(res.data.email);
},
onError: (err) => {
console.error(err);
setEmailErr('error loading data');
},
},
);
Why would this happen? Isn't this repeated as I already checked the local storage one in the useAuth?
9 Replies
manual-pink
manual-pinkOP3y ago
@julien Since we just talked about component A and component B in another thread. This strange behavior only happens in component B, but not in component A. Or component C which doesn't use the same queryKey anywhere else.... I am just wondering why? The error was actually why I was thinking about ditching the useQuery in component B and use that reading from queryClient... but that doesn't seem to be a good strategy. Now I somehow fixed the error by that extra line, but it doesn't make sense to me why this would fix it.
ambitious-aqua
ambitious-aqua3y ago
And in this component I have console.log and see that we definitely have the token, it's not null or undefined. However, in my useQuery it will result in some data fetching error.
Can you share the code including the usage of useQuery and the console.log, and also provide details about the data fetching error?
manual-pink
manual-pinkOP3y ago
unfortunately that backend part I can't share.. but I can write a bit in the above. The error was 401, meaning unauthorized, which means somehow the token might not be attached. I wrote a simplified component B. The part that doesn't make sense to me is that additional check for token. I want to just use that accessToken I got from useAuth, since I already did that localstorage check there.
ambitious-aqua
ambitious-aqua3y ago
When is the authToken stored in localStorage? If it is stored after useState<string | null>(localStorage.getItem(ACCESS_TOKEN) ?? null); is called, the state will also need to be refreshed by calling setAccessToken.
manual-pink
manual-pinkOP3y ago
After login, we get a refresh token, we use that to exchange access token. If use chooses (keep me logged in), then both are stored in local storage, if not checked, nothing is stored in local storage. so... when not checked, basically we are not check local storage and totally rely on our useAuth for tokens ... this is where it got me confused.
ambitious-aqua
ambitious-aqua3y ago
I would try this:
const [accessToken, setAccessToken] = useState<string | null>(()=>{
const value = localStorage.getItem(ACCESS_TOKEN) ?? null;
console.log('Storing token to state', value);
return value;
});
const [accessToken, setAccessToken] = useState<string | null>(()=>{
const value = localStorage.getItem(ACCESS_TOKEN) ?? null;
console.log('Storing token to state', value);
return value;
});
If it logs Storing token to state: null that means the token is not yet in localstorage at the time the state is initialized. If that's the case it'll remain null until it is updated with setAccessToken.
manual-pink
manual-pinkOP3y ago
great tip, I will give it a debug Ok, after poking around, I decided to add extra check, such as
// fetch data
const {isLoading: isLoadingEmail} = useQuery(
['emailData', token],
async () => {
if (token){
return await axiosClient.get(ACCOUNT_EMAIL_URL, {
params: {
token,
},
});
}
},
{
onSuccess: (res) => {
setEmail(res.data.email);
},
onError: (err) => {
console.error(err);
setEmailErr('error loading data');
},
},
);
// fetch data
const {isLoading: isLoadingEmail} = useQuery(
['emailData', token],
async () => {
if (token){
return await axiosClient.get(ACCOUNT_EMAIL_URL, {
params: {
token,
},
});
}
},
{
onSuccess: (res) => {
setEmail(res.data.email);
},
onError: (err) => {
console.error(err);
setEmailErr('error loading data');
},
},
);
In that way, only when token or other things needed are fetched, we do that useQuery call. Otherwise it will call as soon as possible and result in some error when network is delayed.
ambitious-aqua
ambitious-aqua3y ago
If you want the query to be disabled when the token is null, you can also use the enabled option: enabled: !!token.
manual-pink
manual-pinkOP3y ago
oh nice to know! Ok, so I suspect there is sth wrong with the BE for this. As the error is not always reproducible.. but at least adding the checks our UI looks fine for the moment. We still have some error in console but it should not come from UI then, since we add that enabled check.

Did you find this page helpful?