T
TanStack13mo ago
environmental-rose

What does the `@tanstack/react-query-next-experimental` package do exactly?

From the docs:
This package will allow you to fetch data on the server (in a Client Component) by just calling useSuspenseQuery in your component. Results will then be streamed from the server to the client as SuspenseBoundaries resolve. If you call useSuspenseQuery without wrapping it in a <Suspense> boundary, the HTML response won't start until the fetch resolves. This can be when you want depending on the situation, but keep in mind that this will hurt your TTFB.
The statement above is under the heading Experimental streaming without prefetching in Next.js on the Advanced SSR page. My first question is, - Is there a difference in the behaviour of useSuspenseQuery when data is prefetched vs when data isn't? Without any additional setup, I would expect useSuspenseQuery to just trigger suspense, and cause the parent tree (up to the closest <Suspense> if any) to suspend, while not affecting streaming of other streamable parts. I tried this by modifying the streaming suspense example and everything seems to work fine. The original example is at: https://tanstack.com/query/latest/docs/framework/react/examples/nextjs-suspense-streaming (Note that the example as embedded on this page uses StackBlitz, which causes an error. You can access the example on codesandbox here: https://codesandbox.io/p/devbox/github/tanstack/query/tree/main/examples/react/nextjs-suspense-streaming) Here's my modified CodeSandbox: https://codesandbox.io/p/devbox/serene-leakey-dcvpmx This modified version simply removes the ReactQueryStreamedHydration used to wrap the app in providers.tsx. With this removal, everything still seems to still work fine. The parts wrapped in suspense are still streamed normally without prefetching. My second question is: - What is the purpose of @tanstack/react-query-next-experimental, and in particular, the ReactQueryStreamedHydration component?
3 Replies
environmental-rose
environmental-roseOP13mo ago
When I remove the <Suspense> around any of the wrapped components, everything works fine too, without the ReactQueryStreamedHydration component (no HTML is returned until the component resolves), which is what I expect.
continuing-cyan
continuing-cyan13mo ago
"everything works fine" is not entirely true because the data that is fetched on the server never winds up in the client side cache without the plugin. you will see the result on the screen because it "renders" to html, but it won't be in the client side cache. The query devtools should show that
environmental-rose
environmental-roseOP13mo ago
Thanks. I just read through the source. It looks like the ReactQueryStreamedHydration is just making the data available on the client by storing it on window via a custom script tag inserted with useServerInsertedHTML. One more thing though. I was expecting that the rendered HTML would be immediately overridden by the fallback on the client since useSuspenseQuery will trigger suspense on the client (when not using the ReactQueryStreamedHydration component). However, if the suspending component results in the same value as the server-rendered HTML (probably not the best way to put it), then the fallback isn't rendered. For example, given the following:
<Suspense fallback={<div>waiting 6000....</div>}>
<div>{Math.random()}</div>
<MyComponent wait={6000} />
</Suspense>
<Suspense fallback={<div>waiting 6000....</div>}>
<div>{Math.random()}</div>
<MyComponent wait={6000} />
</Suspense>
On the client, the fallback is first rendered, then the server-rendered HTML (very briefly), and then the fallback is rendered again, and then the HTML is rendered when the fetch is completed on the client, which I believe is because of the Math.random(). If I remove the random part, then the fallback is not re-rendered when the query is fetching on the client. This is a React thing, right?

Did you find this page helpful?