From a1ce3c4ad7024156acad5d05f08d6767459219d1 Mon Sep 17 00:00:00 2001 From: Ryan Miller Date: Wed, 17 Jul 2024 19:53:10 +1000 Subject: [PATCH] docs: Update Streaming with Server Components docs to reflect correct usage (#7725) * chore: update Streaming with Server Components docs to reflect correct usage * chore: update Streaming with Server Components to show moving the getQueryClient function * chore: fix prettier styling --------- Co-authored-by: Dominik Dorfmeister --- docs/framework/react/guides/advanced-ssr.md | 30 +++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/docs/framework/react/guides/advanced-ssr.md b/docs/framework/react/guides/advanced-ssr.md index 10ac86c69c..bbbac63208 100644 --- a/docs/framework/react/guides/advanced-ssr.md +++ b/docs/framework/react/guides/advanced-ssr.md @@ -365,7 +365,9 @@ With the prefetching patterns described above, React Query is perfectly compatib As of React Query v5.40.0, you don't have to `await` all prefetches for this to work, as `pending` Queries can also be dehydrated and sent to the client. This lets you kick off prefetches as early as possible without letting them block an entire Suspense boundary, and streams the _data_ to the client as the query finishes. This can be useful for example if you want to prefetch some content that is only visible after some user interaction, or say if you want to `await` and render the first page of an infinite query, but start prefetching page 2 without blocking rendering. -To make this work, we have to instruct the `queryClient` to also `dehydrate` pending Queries. We can do this globally, or by passing that option directly to `hydrate`: +To make this work, we have to instruct the `queryClient` to also `dehydrate` pending Queries. We can do this globally, or by passing that option directly to `hydrate`. + +We will also need to move the `getQueryClient()` function out of our `app/providers.jsx` file as we want to use it in our server component and our client provider. ```tsx // app/get-query-client.ts @@ -378,8 +380,7 @@ function makeQueryClient() { staleTime: 60 * 1000, }, dehydrate: { - // per default, only successful Queries are included, - // this includes pending Queries as well + // include pending queries in dehydration shouldDehydrateQuery: (query) => defaultShouldDehydrateQuery(query) || query.state.status === 'pending', @@ -387,6 +388,22 @@ function makeQueryClient() { }, }) } + +let browserQueryClient: QueryClient | undefined = undefined + +export function getQueryClient() { + if (isServer) { + // Server: always make a new query client + return makeQueryClient() + } else { + // Browser: make a new query client if we don't already have one + // This is very important, so we don't re-make a new client if React + // suspends during the initial render. This may not be needed if we + // have a suspense boundary BELOW the creation of the query client + if (!browserQueryClient) browserQueryClient = makeQueryClient() + return browserQueryClient + } +} ``` > Note: This works in NextJs and Server Components because React can serialize Promises over the wire when you pass them down to Client Components. @@ -439,7 +456,7 @@ If you're using non-JSON data types and serialize the query results on the serve import { QueryClient, defaultShouldDehydrateQuery } from '@tanstack/react-query' import { deserialize, serialize } from './transformer' -export function makeQueryClient() { +function makeQueryClient() { return new QueryClient({ defaultOptions: { // ... @@ -452,6 +469,8 @@ export function makeQueryClient() { }, }) } + +// ... ``` ```tsx @@ -461,11 +480,12 @@ import { HydrationBoundary, QueryClient, } from '@tanstack/react-query' +import { getQueryClient } from './get-query-client' import { serialize } from './transformer' import Posts from './posts' export default function PostsPage() { - const queryClient = new QueryClient() + const queryClient = getQueryClient() // look ma, no await queryClient.prefetchQuery({