How to update router context globally within `beforeLoad`?
I have a layout route
"/admin/_authenticated". I want to check context's isAuthenticated property in beforeLoad method of this route and update the context in such a way that the updated context is immediately reflected everywhere, as if I'm updating a global variable. Global variable technique works fine, but I think it's not a clean way of doing that.
My use case: Implementing cookie-based auth. Backend is separate (Express). The idea is to check whether session is active on initial load, and if so, to update isAuthenticated key of context, accordingly; otherwise, to redirect to login route. The problem is that the context keeps being stale on beforeLoad calls executed when redirecting user among sibling routes.
Another approach would be to use a custom React Context hook, but there is no convenient way to "inject" the hook into the router like it's done in Tanstack Router (example).
Thank you for building such a great toolchain.26 Replies
harsh-harlequin•2mo ago
you can use
RouterContextProvider imported from @tanstack/react-routerfascinating-indigoOP•2mo ago
@Amos do you have a minimum working piece of code specifically for that part?
I wrote this, but
adminAuth is undefined:
harsh-harlequin•2mo ago
something like this
fascinating-indigoOP•2mo ago
and where do you include
SessionProvider?harsh-harlequin•2mo ago
in
root.tsxfascinating-indigoOP•2mo ago
Same, but it gives error:
TypeError: Cannot read properties of undefined (reading 'subscribe')I'm investigating it. Thank you!
harsh-harlequin•2mo ago
what are you using for auth?
fascinating-indigoOP•2mo ago
On login, http-only cookie is sent in response by Express.
On initial page load, user session is validated by calling the API
GET /me with the cookie included in request headers. At this point, I want to update auth state in React Context.
harsh-harlequin•2mo ago
I don't know what the
.subscribe error is or if it has anything to do with thisfascinating-indigoOP•2mo ago
Yeah, it's strange.
@Manuel Schiller I'd appreciate your thoughts as well.
Btw, if I replace this in
__root.tsx:
with this:
it works fine.harsh-harlequin•2mo ago
why are you using
getRouter and not useRouter?fascinating-indigoOP•2mo ago
Oh.. thanks, now the error is resolved.
But react context does not get merged with router context.
quickest-silver•2mo ago
can you please create a complete minimal example project?
fascinating-indigoOP•2mo ago
quickest-silver•2mo ago
this wont work
why do you want to store this in a react context?
how would this even work when hydrating?
fascinating-indigoOP•2mo ago
On initial load of the app, in
beforeLoad method of the pathless layout route, I want to fetch GET /me for checking whether user's current session is valid, and if so, to let the user in to the current guarded route; otherwise, to redirect the user to login route. As the pathless layout route's beforeLoad method is being called each time a child route is visited, I want to make sure that subsequent beforeLoad calls after the first one contains isAuthenticated set to true in their context.
What would be the correct way of achieving that? Looks like my understanding of the techniques applied by the framework is shallow.quickest-silver•2mo ago
just put this into the router context then
not a react context
fascinating-indigoOP•2mo ago
When I return an updated part of context inside beforeLoad in the pathless layout route, child routes of that route get updated (merged) context, but next beforeLoad call of the layout route keeps having stale version of the context.
Am I missing something in your approach?
quickest-silver•2mo ago
I mean router context
not route context
fascinating-indigoOP•2mo ago
Something like this?
1. In
getRouter function in router.tsx, fetch GET /me, and add the result to context object as isAuth key in createRouter function call.
2. Read context.isAuth inside beforeLoad method and act accordingly.
3. Invalidate router context, whenever user logs in, logs out explicitly, or logs out implicitly due to getting 401 error due to cookie session being expired.rival-black•2mo ago
I think this is what Manual means:
this will always have updated data. at least that's how I've implemented it. You can then use component's own context to access the user.
fascinating-indigoOP•2mo ago
Thanks for sharing. It surely works, but it repeats
getUser call on each route navigation, because the root route's beforeLoad gets called on each route navigation. I want to prevent unnecessary load directed to backend.rival-black•2mo ago
right. you can cache it with queryClient and invalidate it when user logs out or time based revalidation.
@ziyaddinsadygly did you find the solution?
fascinating-indigoOP•2mo ago
Nope.
I'm exploring equivalent mechanisms in the other SSR frameworks.
continuing-cyan•2mo ago
You can create a provider and use it on client side to avoid call beforeLoad to check user.
fascinating-indigoOP•2mo ago
Yeah, looks like context provider on client side will do the job, because, apparently, CSR-based pages do not require "instant" redirection, and SSR-based pages will be fine by just loading public data (that is, data that does not require auth), at least for now.
Thank you for your reply, Carlos.