Routing with async data
Consider the following setup where my context has
user: User | null:
Note that useUser is a react query. On direct navigation to this page I want to check this users permissions list, and redirect them if they don't have it
How can I achieve this, as user is initially null until the data loads from the query - redirecting them every time? Would I have to add some kind of loading into the context and catch that at a higher level perhaps for all pages this might affect?27 Replies
harsh-harlequin•16mo ago
I have the exact same problem
stormy-gold•16mo ago
If your user if in react-query, why not just make sure the user is there and then read the permissions
Optionally, whenever the user in React Query changes, you could set up a useEffect to call
router.invalidateharsh-harlequin•16mo ago
Hi Sean
import { createFileRoute, redirect } from '@tanstack/react-router'
import { useRouteContext } from '@tanstack/react-router';
export const Route = createFileRoute('/dashboard')({
component: Dashboard, // Add semicolon here
beforeLoad: async ({ context, location }) => {
console.log(context.user)
if (!context.user) {
throw redirect({
to: '/login',
search: {
redirect: location.href,
},
});
}
},
})
function Dashboard() {
const context = useRouteContext({from: "/dashboard"});
const user = context.user;
return (
<div className="p-2">
<h3>Welcome to Dashboard!</h3>
User is {"YOLO"} ,
{user && user.email}
<br />
{user?.displayName}
</div>
)
}
this is my component
when I refresh this seems to go to redirect always and user also seems nullstormy-gold•16mo ago
You need to first wait for the user call to resolve.
Only then should you be calling redirect.
You can use either of the solutions I mentioned above. If your user is not in React Query, rather just in react context, then just use the
router.invalidate() call, or even just wait till that request has resolved before rendering the <RouterProvider />stormy-gold•16mo ago
Like what I've done here.
https://github.com/SeanCassiere/nv-rental-clone/blob/508800863fb2936a6e819e5e14b082984d9fccd7/src/entry-app.tsx#L22-L36
GitHub
nv-rental-clone/src/entry-app.tsx at 508800863fb2936a6e819e5e14b082...
Navotar with Tailwind and the Tanstack. Contribute to SeanCassiere/nv-rental-clone development by creating an account on GitHub.
harsh-harlequin•16mo ago
cool, thank you
that fixed the issue, I had to wait for the user call to be resolved @ auth things ,
sensitive-blueOP•16mo ago
Cool. thanks for answering that for me. Will give it a go today!
Aha, that check in the useEffect sorted the issue for me:
if (typeof auth.user === "undefined") return;
I'll consider the other solution toostormy-gold•16mo ago
This is definitely library/implementation specific.
It's why we don't prescribe a way of doing auth, since everyone does auth just differently enough that you end up having so many variations 😅.
conscious-sapphire•16mo ago
What if I want to show a loader on specific pages instead of all app
For example on the following code snippet:
stormy-gold•16mo ago
Since you are abstracting away the
createRoute function, you'll find this difficult. Normally you'd just set the pendingComponent property when creating a route.
You could use a layout route to handle all the auth work and surgically set the pending components.
I'd go for a public/authed set of layout routes that have no real UI layer, but rather just used for checking auth on navigate.
Something like what I've done here https://github.com/SeanCassiere/nv-rental-clone/tree/master/src/routes
I'd stay away from that abstraction on createRoute since that breaks type-safety and makes it a burden in your code-base whenever you want to implement any of the native features.GitHub
nv-rental-clone/src/routes at master · SeanCassiere/nv-rental-clone
Navotar with Tailwind and the Tanstack. Contribute to SeanCassiere/nv-rental-clone development by creating an account on GitHub.
sensitive-blueOP•16mo ago
I’ll consider the other way too for sure. It seems a nice way to integrate with react query
Finally got back round to this again. I'm still having a slight issue as my
useUser is actually an authenticated endpoint which relies on isAuthenticated (just checking for tokens)
useUser has the following:
Is it an issue that on logout, my ['user', true] still has the user data in it?
Could I just stick a useEffect on isAuthenticated and use removeQueries on the user?
Currently on logout I have it set to invalidate the user query, which will be calculated on login again, but it still does one extra call to the useUser endpoint... (and I can see the user data in the cache under ['user', true]stormy-gold•16mo ago
Yup, or just perform a
invalidateQueries call.sensitive-blueOP•16mo ago
Would the data not remain in the query cache until the user logs in again? Is there any danger in that?
stormy-gold•16mo ago
Thats IMO more of a "its up to decision". Questions like
"Realistically, are multiple users sharing the same devices using the same tab instance?"
are what you'd need to consider.
sensitive-blueOP•16mo ago
Ah I see. I was considering danger in someone logging out and leaving their pc open or something along those lines
Thanks for the response
Honestly I'd just like to do a
queryClient.reset() on logout or just remove every query key (removeQueries). But as soon as I do that it seems to try to do network calls for all active queries - so I'd have to wait until the user gets to the login page and then call reset, or call reset which triggers every query..?
Is removeQueries even supposed to trigger a refetch?stormy-gold•16mo ago
I suppose it might, if that's query's observer (useQuery) is still active.
sensitive-blueOP•16mo ago
How confusing 🥲
The issue seems to be:
- When I logout I set isAuthenticated to false and try to removeQueries
- isAuthenticated change triggers a re-render in
App
- re-render causes hooks to try to fetch again
- isAuthenticated causes router to invalidate kicking user to login
I don't see a way round thisfascinating-indigo•16mo ago
can you reproduce this in a minimal complete example?
ideally fork one of the router examples on stackblitz
sensitive-blueOP•16mo ago
Sorry can you point me in the direction of those, seems to be quite a few results for that
fascinating-indigo•16mo ago
React TanStack Router Basic File Based Example | TanStack Router Docs
An example showing how to implement Basic File Based in React using TanStack Router.
fascinating-indigo•16mo ago
there are lots of examples on the left side
fascinating-indigo•16mo ago
choose one that fits best

sensitive-blueOP•16mo ago
Ah yeah I remembered seeing it somewhere. Cheers
I finally reprod it
sensitive-blueOP•16mo ago
StackBlitz
Router Kitchen Sink React Query File Based Example (forked) - Stack...
Run official live example code for Router Kitchen Sink React Query File Based, created by Tanstack on StackBlitz
sensitive-blueOP•16mo ago
As soon as I add useLocation it does not do what I intend (cache remains uncleared from extra server call)
Remove that line, and works as expected
To use:
Log in, go to “secret” page, press logout. Cache not cleared and extra call to server made.
There’s a bunch of faff code as I was trying to repro
I mean the clear fix on my local is to not use useLocation
Cleaned the code now:
https://stackblitz.com/edit/tanstack-router-jnuq6i?file=src%2Froutes%2F_authenticated%2Fsecret.tsx
Repro:
Log in, go to “secret” page, press logout. Cache not cleared (0 watchers) and extra call to server made.
As soon as I add in
const location = useLocation() that occurs.
I can raise it as an issue.fascinating-indigo•16mo ago
when you add
const location = useLocation(); to secret.tsx, this component will re-render each time the location changes
which will also re-run your hookssensitive-blueOP•16mo ago
Hmm I see, so there is no real solution
I’ll just not use useLocation then