Client-only router context
With TanStack Router (without Start) we can pass context from a React Context by putting the
<RouterProvider>
inside the React Context provider and passing the context
prop. https://tanstack.com/router/latest/docs/framework/react/guide/router-context#how-about-using-react-contexthooks
But in TanStack Start there is <StartClient>
instead of <RouterProvider>
and it doesn't take context
.
My use case right now is in migrating a Router app to Start so that we can get some dynamic SSR injection into the root route but have all other routes disable SSR with the new selective SSR. Our app's loaders can't be isomorphic so what I am doing now is creating a layout under the root route to initialize the client-side context values but these get recreated every time that beforeLoad
runs which is every navigation. This is different than the Router case where we would initialize the router with those context values so the initialization wouldn't be in a loader.
I might be missing an obvious pattern to achieve what I need. I'm sure there is a way to also just have client-only initialization and access those in client-only loaders such as initializing them in client.tsx
but it feels less "elegant" than the context pattern in Router.15 Replies
wise-white•2mo ago
why can't they be isomorphic?
you would need to disable SSR then for those routes I guess?
optimistic-goldOP•2mo ago
Our auth solution is client-centric and and needs client-side initialization and reads local storage
We are working towards moving to a different auth solution (Clerk) that would enable auth in SSR but for now not sure what the best solution is
I'm using
defaultSsr: false
and only have ssr: true
on the root route. But yes all of our other routes don't have SSR enabledwise-white•2mo ago
so then don't SSR those routes
loaders won't run on the client then
optimistic-goldOP•2mo ago
Yes, my question is more about if there's a way to seed router context client-only. So if I have an
Auth
instance that can only be provided starting on the client is there a way to get that into the router context so it can be used by loaders? Right now I am initializing it in a beforeLoad
in a pathless layout but this gets re-run for every navigation.wise-white•2mo ago
so do you need this context to live I react land?
btw you should be able to distinguish the initial
beforeLoad
invocation from the others using the cause
that is passed in
we are also working on adding new lifecycle methods that would allow you to accomplish exactly what you need, one would be called with the same caching semantics as loader
not there yet though
feeding something into StartClient
feels wrong as this would break the "server has the same data as client on root" premiseoptimistic-goldOP•2mo ago
The values of the context do not have to be inside React, but perhaps it's best that it is injectable into the router context. I imagine there is a solution where in
client.tsx
we just have:
and then just import { auth } from "@/client.tsx"
for use in the client loaders.
Yes I think doing that injection through StartClient
would not make sense, but with selective SSR (especially because of the more-restrictive inheritance) perhaps there could be an API for "this route and its children are not SSR'd, so we can inject client-only context"wise-white•2mo ago
btw you can also do ssr:false on the root route and put your html shell into
shellComponent
then you can avoid the pathless layout in betweenoptimistic-goldOP•2mo ago
How can I get a value coming from the server in that case? For example if I want to pass a value from the server I would do it through the context and keep ssr: true on the root.
wise-white•2mo ago
how is that value "coming from the server"?
optimistic-goldOP•2mo ago
It's dynamic depending on the environment variables on the server process
(configuration of our build and deploy pipeline means we can't just rebuild the app with different environment variables for different environments, so the environment variables are provided in the process.env at runtime)
wise-white•2mo ago
you could just use
dehydrate
and hydrate
thenoptimistic-goldOP•2mo ago
This is a TanStack Query API?
wise-white•2mo ago
no
router
optimistic-goldOP•2mo ago
Ah ok, thanks! Will take a look - appreciate the discussion
I'm finding that with
defaultSsr: false
and no ssr: true
in __root.tsx
that there is some invisible error and no page gets delivered to the browser. I suppose this is a pretty uncommon case for one using TanStack Start but was wondering if this is the intended behavior. If I add ssr: true
to the root route I can keep child routes with SSR disabled just fine.wise-white•2mo ago
it's not documented yet, but you can use shellComponent on the root and put your <html> shell in there
that shell MUST always be rendered
https://github.com/TanStack/router/blob/main/examples/react/start-basic/src/routes/__root.tsx#L62