#Client-only router context

30 messages · Page 1 of 1 (latest)

spring briar
#

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.

eager juniper
#

why can't they be isomorphic?

#

you would need to disable SSR then for those routes I guess?

spring briar
#

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 enabled

eager juniper
#

so then don't SSR those routes

#

loaders won't run on the client then

spring briar
#

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.

eager juniper
#

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" premise

spring briar
#

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:

export const auth = new Auth();

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"

eager juniper
#

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 between

spring briar
#

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.

eager juniper
#

how is that value "coming from the server"?

spring briar
#

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)

eager juniper
#

you could just use dehydrate and hydrate then

spring briar
#

This is a TanStack Query API?

eager juniper
#

no

#

router

spring briar
#

Ah ok, thanks! Will take a look - appreciate the discussion

spring briar
#

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.

eager juniper
#

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