diff --git a/docs/framework/react/guides/suspense.md b/docs/framework/react/guides/suspense.md index 368a331ac1c..78c3de8a461 100644 --- a/docs/framework/react/guides/suspense.md +++ b/docs/framework/react/guides/suspense.md @@ -122,8 +122,40 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import * as React from 'react' import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental' +function makeQueryClient() { + return new QueryClient({ + defaultOptions: { + queries: { + // With SSR, we usually want to set some default staleTime + // above 0 to avoid refetching immediately on the client + staleTime: 60 * 1000, + }, + }, + }) +} + +let browserQueryClient: QueryClient | undefined = undefined + +function getQueryClient() { + if (typeof window === 'undefined') { + // 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 + // supsends 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 + } +} + export function Providers(props: { children: React.ReactNode }) { - const [queryClient] = React.useState(() => new QueryClient()) + // NOTE: Avoid useState when initializing the query client if you don't + // have a suspense boundary between this and the code that may + // suspend because React will throw away the client on the initial + // render if it suspends and there is no boundary + const queryClient = getQueryClient() return ( diff --git a/examples/react/nextjs-suspense-streaming/src/app/providers.tsx b/examples/react/nextjs-suspense-streaming/src/app/providers.tsx index 840ccde40dd..fb0f5a24e97 100644 --- a/examples/react/nextjs-suspense-streaming/src/app/providers.tsx +++ b/examples/react/nextjs-suspense-streaming/src/app/providers.tsx @@ -1,4 +1,3 @@ -// app/providers.jsx 'use client' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' @@ -6,17 +5,29 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools' import * as React from 'react' import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental' +function makeQueryClient() { + return new QueryClient({ + defaultOptions: { + queries: { + staleTime: 60 * 1000, + }, + }, + }) +} + +let browserQueryClient: QueryClient | undefined = undefined + +function getQueryClient() { + if (typeof window === 'undefined') { + return makeQueryClient() + } else { + if (!browserQueryClient) browserQueryClient = makeQueryClient() + return browserQueryClient + } +} + export function Providers(props: { children: React.ReactNode }) { - const [queryClient] = React.useState( - () => - new QueryClient({ - defaultOptions: { - queries: { - staleTime: 5 * 1000, - }, - }, - }), - ) + const queryClient = getQueryClient() return (