TanStack / router

🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering.
https://tanstack.com/router
MIT License
7.72k stars 563 forks source link

useRouteContext initially undefined #1635

Open InsideGH opened 3 months ago

InsideGH commented 3 months ago

Describe the bug

When loading the page, 'useRouteContext' is undefined. When client side navigating to the page, it's defined.

Your Example Website or App

https://tanstack.com/router/latest/docs/framework/react/examples/basic-ssr-file-based

Steps to Reproduce the Bug or Issue

It's can be reproduced in the "basic-ssr-file-based" example. If you go from "home" to "post" in browser, the context is defined. If you reload the page while standing on "post" page, it's undefined.

Screenshot from 2024-05-19 17-12-17

Expected behavior

useRouteContext being defined both during SSR load and Client side routing.

Screenshots or Videos

No response

Platform

Linux

Additional context

No response

SeanCassiere commented 3 months ago

I've tested this using the "basic-ssr-file-based" in the sandbox below (with all the packages upgraded to latest). In the sandbox below, I was not able recreate the issue you described.

https://stackblitz.com/edit/github-djwvqx?file=src%2Froutes%2Fposts%2Findex.tsx

Please attach a minimal reproduction of the issue you facing with any steps required to replicate the scenario to observe the issue.

lithdew commented 3 months ago

@SeanCassiere was able to reproduce it in the sandbox you linked. Navigating to /posts and refreshing the page causes a hydration error and: PostsIndexComponent.context undefined

image
SeanCassiere commented 3 months ago

Reproduction steps:

  1. Open the stackblitz example and open the preview in a new tab.
  2. Directly visit /posts/.
  3. Observe the error message on the screen and in the console.
  4. Observe the hydration failure message in the console.

Edit: I haven't seen this behaviour on client-side rendering ONLY apps.

idonov commented 1 month ago

I have this same issue right now. When using SSR the context for the first paint on the client is undefined.

My use case is I am setting the page title in the __root.tsx meta section from the context, when on the server context is there, when navigating on the client the context is there, just on the initial paint on the client the context is undefined. I am not even expecting my server context to be there, the initial context from the createRoute is missing on the client as well.

lithdew commented 1 month ago

Wanted to bump with the recent #1907 being merged, that this issue still exists.

With the code snippet Route.useRouteContext({ select: (ctx) => { console.log(ctx); return ctx; }), ctx will, initially on page load, be printed out in the browser as undefined.

tannerlinsley commented 1 month ago

Curious what your use case is here, because this is a tricky situation...

Context is guaranteed to be available by the time beforeLoads and loaders are called, but hydration is quite different because it can't be asynchronous. Everything needs to be available and ready to render by the time we call root.hydrate(). So while data from loaders, etc are serialized down to the client during SSR, context is not. This is primarily because the things we put into context aren't serializable, e.g. something like QueryClient.

So a few key points:

What I propose:

lithdew commented 1 month ago

@tannerlinsley I posted a question recently on Discord that could describe the use case of wanting to serialize "some" asynchronous context values to the client in the case of accessing route context in meta.

If I use

meta: ({match: { routeContext: { someField } } }) => { ... }

or

meta: ({match: { context : { someField } } }) => { ... }

... in both cases, they are undefined. I do not want to have the data I am accessing in meta be returned in the loader, because the data was loaded in a parent match's beforeLoad function. Having the data returned in loader will serialize it to the client and cause the data to be duplicated in the initial SSR'd HTML payload.