Router context invalidate Promise resolve does not invalidate context
Describe the bug
In the code below, which was suppose to invalidate the context and navigate to the following route. for context i'm following the example given in tanstack authenticated routes example. Even after navigation the context isn't invalidated which I can see in console log. It results in redirect to login page not working properly after clicking logout and just stuck in the "/" page.
router.invalidate().finally(() => { navigate({ to: "/" }); });
It only invalidates or I can see it invalidates when I manually reload the page, which means during the navigation the context doesn't invalidate.
PS: I do have an api request in the logout function.
Your Example Website or App
...
Steps to Reproduce the Bug or Issue
Following the tanstack example locally.
https://stackblitz.com/edit/tanstack-router-4achrw?file=src%2Froutes%2F_auth.tsx
Expected behavior
Router context should've been already invalid in .finally or .then even before navigating.
Screenshots or Videos
No response
Platform
- OS: [e.g. macOS, Windows, Linux]
- Browser: [e.g. Chrome, Safari, Firefox]
- Version: [e.g. 91.1]
Additional context
No response
i got same issue, and stuck with this, any solution ? when i am use authenticated using local storage, there is no problem, but when using api, not navigate after login success
i got same issue, and stuck with this, any solution ? when i am use authenticated using local storage, there is no problem, but when using api, not navigate after login success
Still no reply from the devs as of now
same issue here
can you please provide a minimal complete example by forking one of the router examples on stackblitz?
can you please provide a minimal complete example by forking one of the router examples on stackblitz?
https://stackblitz.com/edit/tanstack-router-4achrw?file=src%2Froutes%2F_auth.tsx
Here a link to a fork, I've only made one change to this, instead of navigating to "/" which is a public route, it navigates to "login", which shouldn't be a problem if context is invalidated, however it isn't. so even after clicking logout, it doesn't go back to "login" route.
Same here while using supabase auth api. No issue when working with local storage.
This is not working : https://tanstack.com/router/latest/docs/framework/react/guide/router-context#invalidating-the-router-context
update guys, the current hack seems to use sleep(1000) as explained here :
https://github.com/TanStack/router/discussions/1668
// This is just a hack being used to wait for the auth state to update
// in a real app, you'd want to use a more robust solution
await sleep(1)
This trick works on my side, but this is a serious issue with Context.
PS: the sleep function is quite obvious :
export async function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
I'm currently using the flushSync solution as a workaround following suggestion by SzelamC at https://github.com/TanStack/router/discussions/1668#discussioncomment-9726727
I'm currently using the flushSync solution as a workaround following suggestion by SzelamC at #1668 (reply in thread)
So where should I use flushSync regarding this issue?
Thanks @ilia-luk, it works great, I didn't thought about this solution.
@ZahidHasan321 use flushSync in your AuthProvider when you set your new user/session state like in the thread mentionned by @ilia-luk .
I've noticed that the issue was not there in version 1.16.0 of @tanstack/react-router, but it was found in the latest release, version 1.56.1. Could you provide a proper solution or let us know if there is a patch release available?
Got same issue here
"@tanstack/react-router": "^1.95.3", "react": "^19.0.0", "react-dom": "^19.0.0",
Same here. I am updating the context passed to the router, but while the context's value gets updated correctly, the loader functions that are triggered with router.invalidate() still load the older context value.
Only when the route is reloaded manually the router shows the updated context.
I've tried doing this with any given combination of useState, useEffect and contextProvider and still same result.
As others have mentioned, a workaround for this involves using some kind of synchronous external store instead of the router context (in my case, I am using Tanstack Query, so I am grabbing the queryClient from the router context and using queryClient.getQueryData to get the updated value).
I also encountered this problem and found that context does not always update correctly when calling router.invalidate().
Previously, I used beforeLoad like this:
beforeLoad: (props) => {
const isPublic = !!props.matches.find(match => match.id === '/pu');
const isPrivate = !!props.matches.find(match => match.id === '/pr');
const isAuthenticated = props.context.auth.isAuthenticated;
if (isAuthenticated !== undefined) {
if (isAuthenticated) {
if (isPublic) {
throw redirect({ to: '/pr' });
}
} else {
if (isPrivate) {
throw redirect({ to: '/pu' });
}
}
}
};
However, I noticed that context does not always update properly after router.invalidate().
As a temporary workaround, I moved the authentication check to the root component like this:
const isAuthenticated = useMemo(() => (isFetched ? isSuccess : undefined), [isFetched, isSuccess]);
const navigate = useNavigate();
const isMatchPrivate = useMatches({
select(matches) {
return matches.some(match => match.fullPath === LayoutRoutePrivate.fullPath);
}
});
const isMatchPublic = useMatches({
select(matches) {
return matches.some(match => match.fullPath === LayoutRoutePublic.fullPath);
}
});
useEffect(() => {
if (isAuthenticated !== undefined) {
if (isMatchPrivate) {
if (!isAuthenticated) navigate({ to: '/pu' });
} else if (isMatchPublic) {
if (isAuthenticated) navigate({ to: '/pr' });
}
}
}, [isAuthenticated, isMatchPrivate, isMatchPublic, navigate]);
This approach ensures that authentication status is always checked based on updated state. However, it would be great to have a proper fix for beforeLoad so that context updates correctly after router.invalidate().
Yeah in my view router invalidation is not reliable when it comes to auth. In my case I simply force a reload of the page after login/logout with location.href = '/' to make sure the router's state is completely reset.
I am facing the same issue, on the latest version. Full repro stackblitz: here
I have written some explanatory (hopefully) comments in AuthProviders logoutmethod, as well as in_authenticated/route.tsx`
I have also added strategically placed debuggers to aid you.
Hope it helps, let me know if you need more info @schiller-manuel
Facing the same issue. Currently getting around this by reloading post-invalidation:
onSignOut: () => {
router.invalidate();
router.navigate({ reloadDocument: true });
}
"@tanstack/react-router": "^1.130.12" "react": "^19.1.1" "react-dom": "^19.1.1"
Still experiencing this issue, any progress? seems like tanstack should orchestrate better with react state.......