new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

TanStack Query · React · all subjects

ssr/streaming

14 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Streaming with Server Components and prefetching

The Next.js app router automatically streams content ready to display to the browser along Suspense boundary lines as it becomes available. React Query is compatible with streaming. As data for each Suspense boundary resolves, the content can be rendered and streamed to the browser immediately. With prefetching patterns, this works even with useQuery because suspending happens when awaiting the prefetch.

Dehydrating pending queries for streaming

As of React Query v5.40.0, pending queries can be dehydrated and sent to the client without awaiting all prefetches. This allows kicking off prefetches as early as possible without blocking an entire Suspense boundary, and the data streams to the client as the query finishes. To enable this, configure the QueryClient's dehydrate options with shouldDehydrateQuery that returns true for pending queries using: defaultShouldDehydrateQuery(query) || query.state.status === 'pending'.

Prefetching without await for pending queries

When dehydrating pending queries, Server Component functions don't need to be async and don't need to await prefetches. After calling queryClient.prefetchQuery() without await, wrap components in HydrationBoundary with the dehydrated state. On the client, the Promise is put into the QueryCache, allowing useSuspenseQuery to 'use' the Promise that was created on the server.

Serializing non-JSON data in streaming

For non-JSON data types, specify dehydrate.serializeData and hydrate.deserializeData options in QueryClient defaultOptions to serialize and deserialize data on each side of the HydrationBoundary. This ensures the data in the cache is the same format both on the server and client. In the queryFn, call .then(serialize) on the server, and the deserializeData function will handle deserialization on the client.

Persist Adapter with streaming pending queries

When using the persist adapter with streaming Server Components, configure the persister to only persist successful queries and not pending promises. Set dehydrateOptions with shouldDehydrateQuery: defaultShouldDehydrateQuery to ensure only successfully resolved queries are persisted to storage, preventing serialization issues with pending promises.

ReactQueryStreamedHydration experimental package

The @tanstack/react-query-next-experimental package provides ReactQueryStreamedHydration to enable streaming SSR without prefetching. Wrap your app in ReactQueryStreamedHydration within QueryClientProvider. This allows calling useSuspenseQuery directly in Client Components on the server, with results streamed to the client as SuspenseBoundaries resolve. The downside is that without prefetching, request waterfalls are only flattened on initial page load but remain deep on page navigations, whereas prefetching flattens waterfalls for both initial load and subsequent navigation.

useSuspenseQuery vs useQuery with pending promises

When using streaming with pending queries dehydrated to the client, useSuspenseQuery will suspend and stream the HTML response. Using useQuery instead will not suspend and the component renders in pending status, opting out of server rendering the content.

Request waterfalls comparison: prefetching vs experimental streaming

With Server Components and prefetching, request waterfalls are effectively eliminated both for initial page load and subsequent navigation. The experimental streaming without prefetching approach only flattens waterfalls on initial page load but creates the same deep waterfall on page navigations as the original complex waterfall example: 1. |> JS for Feed, 2. |> getFeed(), 3. |> JS for GraphFeedItem, 4. |> getGraphDataById().

Router integration for scroll restoration

TanStack Query works with scroll restoration implementations provided by routers such as React Router's ScrollRestoration, TanStack Router's scroll restoration, or custom history-based solutions.

Scroll restoration definition and browser behavior

Scroll restoration is the browser feature that scrolls a page to the exact position where you were before you navigated away from that page. This feature has regressed since web applications moved towards client-side data fetching.

TanStack Query removes refetch-induced UI resets for scroll restoration

TanStack Query doesn't implement scroll restoration itself, but it removes one of the biggest causes of broken restoration in single-page applications: refetch-induced UI resets. By keeping previously fetched data in cache and optionally using placeholderData, navigation back to a page can render instantly with stable layout, making scroll restoration reliable when handled by the router.

Scroll restoration works out of box with TanStack Query

Scroll restoration for all queries including paginated and infinite queries works out of the box in TanStack Query. Query results are cached and able to be retrieved synchronously when a query is rendered. As long as queries are cached long enough (the default cache time is 5 minutes) and have not been garbage collected, scroll restoration will work out of the box every time.

Server-side Suspense with NextJs streaming

React Query provides an experimental integration for Suspense on the server via @tanstack/react-query-next-experimental package. This allows fetching data on the server in a client component by calling useSuspenseQuery, with results streamed from server to client as SuspenseBoundaries resolve.

ReactQueryStreamedHydration component setup

// app/providers.tsx 'use client' import { environmentManager, 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 (environmentManager.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 } } export function Providers(props: { children: React.ReactNode }) { // 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 ( <QueryClientProvider client={queryClient}> <ReactQueryStreamedHydration> {props.children} </ReactQueryStreamedHydration> </QueryClientProvider> ) } Wrap your app in ReactQueryStreamedHydration for server-side Suspense streaming with NextJs.

Give your agent this brain