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
foreign-sapphire•14mo ago
I have the exact same problem
stormy-gold•14mo 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.invalidate
foreign-sapphire•14mo 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•14mo 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•14mo 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.
foreign-sapphire•14mo ago
cool, thank you
that fixed the issue, I had to wait for the user call to be resolved @ auth things ,
variable-limeOP•14mo 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•14mo 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 😅.
adverse-sapphire•14mo 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•14mo 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.
variable-limeOP•13mo 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•13mo ago
Yup, or just perform a
invalidateQueries
call.variable-limeOP•13mo ago
Would the data not remain in the query cache until the user logs in again? Is there any danger in that?
stormy-gold•13mo 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.
variable-limeOP•13mo 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•13mo ago
I suppose it might, if that's query's observer (useQuery) is still active.
variable-limeOP•13mo 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 thismetropolitan-bronze•13mo ago
can you reproduce this in a minimal complete example?
ideally fork one of the router examples on stackblitz
variable-limeOP•13mo ago
Sorry can you point me in the direction of those, seems to be quite a few results for that
metropolitan-bronze•13mo 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.
metropolitan-bronze•13mo ago
there are lots of examples on the left side
metropolitan-bronze•13mo ago
choose one that fits best

variable-limeOP•13mo ago
Ah yeah I remembered seeing it somewhere. Cheers
I finally reprod it
variable-limeOP•13mo 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
variable-limeOP•13mo 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.metropolitan-bronze•13mo 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 hooksvariable-limeOP•13mo ago
Hmm I see, so there is no real solution
I’ll just not use useLocation then