Framework
Version
Integrationen

TanStack Query Integration

Wichtig

Diese Integration automatisiert SSR Dehydration/Hydration und Streaming zwischen TanStack Router und TanStack Query. Wenn Sie den Standardleitfaden für External Data Loading noch nicht gelesen haben, beginnen Sie dort.

Was Sie bekommen

  • Automatische SSR Dehydration/Hydration Ihres QueryClient
  • Streaming von Queries, die während des anfänglichen Server-Renderings zum Client aufgelöst werden
  • Redirect-Handling für redirect(), das von Queries/Mutations geworfen wird
  • Optionales Provider-Wrapping mit QueryClientProvider

Installation

Die TanStack Query-Integration ist ein separates Paket, das Sie installieren müssen

sh
npm install -D @tanstack/react-router-ssr-query
# or
pnpm add -D @tanstack/react-router-ssr-query
# or
yarn add -D @tanstack/react-router-ssr-query
# or
bun add -D @tanstack/react-router-ssr-query
npm install -D @tanstack/react-router-ssr-query
# or
pnpm add -D @tanstack/react-router-ssr-query
# or
yarn add -D @tanstack/react-router-ssr-query
# or
bun add -D @tanstack/react-router-ssr-query

Einrichtung

Erstellen Sie Ihren Router und verdrahten Sie die Integration. Stellen Sie sicher, dass in SSR-Umgebungen pro Anfrage ein frischer QueryClient erstellt wird.

tsx
// src/router.tsx
import { QueryClient } from '@tanstack/react-query'
import { createRouter } from '@tanstack/react-router'
import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'
import { routeTree } from './routeTree.gen'

export function createAppRouter() {
  const queryClient = new QueryClient()
  const router = createRouter({
    routeTree,
    // optionally expose the QueryClient via router context
    context: { queryClient },
    scrollRestoration: true,
    defaultPreload: 'intent',
  })

  setupRouterSsrQueryIntegration({
    router,
    queryClient,
    // optional:
    // handleRedirects: true,
    // wrapQueryClient: true,
  })

  return router
}
// src/router.tsx
import { QueryClient } from '@tanstack/react-query'
import { createRouter } from '@tanstack/react-router'
import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'
import { routeTree } from './routeTree.gen'

export function createAppRouter() {
  const queryClient = new QueryClient()
  const router = createRouter({
    routeTree,
    // optionally expose the QueryClient via router context
    context: { queryClient },
    scrollRestoration: true,
    defaultPreload: 'intent',
  })

  setupRouterSsrQueryIntegration({
    router,
    queryClient,
    // optional:
    // handleRedirects: true,
    // wrapQueryClient: true,
  })

  return router
}

Standardmäßig wickelt die Integration Ihren Router mit einem QueryClientProvider. Wenn Sie bereits Ihren eigenen Provider bereitstellen, übergeben Sie wrapQueryClient: false und behalten Sie Ihren benutzerdefinierten Wrapper bei.

SSR-Verhalten und Streaming

  • Während des Server-Renderings dehydriert die Integration anfängliche Queries und streamt alle nachfolgenden Queries, die während des Renderings aufgelöst werden.
  • Auf dem Client hydriert die Integration den anfänglichen Zustand und dann inkrementell gestreamte Queries.
  • Queries von useSuspenseQuery oder Loader Prefetches nehmen an SSR/Streaming teil. Einfache useQuery-Aufrufe werden nicht auf dem Server ausgeführt.

Verwendung in Routen

Verwendung von useSuspenseQuery vs. useQuery

  • useSuspenseQuery: wird auf dem Server während SSR ausgeführt, wenn seine Daten benötigt werden, und wird zum Client gestreamt, sobald sie aufgelöst sind.
  • useQuery: wird nicht auf dem Server ausgeführt; es wird nach der Hydration auf dem Client abgerufen. Verwenden Sie dies für Daten, die nicht für SSR benötigt werden.
tsx
// Suspense: executes on server and streams
const { data } = useSuspenseQuery(postsQuery)

// Non-suspense: executes only on client
const { data, isLoading } = useQuery(postsQuery)
// Suspense: executes on server and streams
const { data } = useSuspenseQuery(postsQuery)

// Non-suspense: executes only on client
const { data, isLoading } = useQuery(postsQuery)

Preload mit einem Loader und Lesen mit einem Hook

Preload kritische Daten im loader der Route, um Wasserfälle und Ladeanzeigen zu vermeiden, und lesen Sie sie dann in der Komponente. Die Integration stellt sicher, dass serverseitig abgerufene Daten während SSR dehydriert und zum Client gestreamt werden.

tsx
// src/routes/posts.tsx
import { queryOptions, useSuspenseQuery, useQuery } from '@tanstack/react-query'
import { createFileRoute } from '@tanstack/react-router'

const postsQuery = queryOptions({
  queryKey: ['posts'],
  queryFn: () => fetch('/api/posts').then((r) => r.json()),
})

export const Route = createFileRoute('/posts')({
  // Ensure the data is in the cache before render
  loader: ({ context }) => context.queryClient.ensureQueryData(postsQuery),
  component: PostsPage,
})

function PostsPage() {
  // Prefer suspense for best SSR + streaming behavior
  const { data } = useSuspenseQuery(postsQuery)
  return <div>{data.map((p: any) => p.title).join(', ')}</div>
}
// src/routes/posts.tsx
import { queryOptions, useSuspenseQuery, useQuery } from '@tanstack/react-query'
import { createFileRoute } from '@tanstack/react-router'

const postsQuery = queryOptions({
  queryKey: ['posts'],
  queryFn: () => fetch('/api/posts').then((r) => r.json()),
})

export const Route = createFileRoute('/posts')({
  // Ensure the data is in the cache before render
  loader: ({ context }) => context.queryClient.ensureQueryData(postsQuery),
  component: PostsPage,
})

function PostsPage() {
  // Prefer suspense for best SSR + streaming behavior
  const { data } = useSuspenseQuery(postsQuery)
  return <div>{data.map((p: any) => p.title).join(', ')}</div>
}

Prefetching und Streaming

Sie können auch mit fetchQuery oder ensureQueryData in einem Loader prefetchen, ohne die Daten in einer Komponente zu konsumieren. Wenn Sie das Promise direkt vom Loader zurückgeben, wird es erwartet und blockiert somit die SSR-Anfrage, bis die Query abgeschlossen ist. Wenn Sie das Promise weder erwarten noch zurückgeben, wird die Query auf dem Server gestartet und zum Client gestreamt, ohne die SSR-Anfrage zu blockieren.

tsx
import { createFileRoute } from '@tanstack/react-router'
import { queryOptions, useQuery } from '@tanstack/react-query'

const userQuery = (id: string) =>
  queryOptions({
    queryKey: ['user', id],
    queryFn: () => fetch(`/api/users/${id}`).then((r) => r.json()),
  })

export const Route = createFileRoute('/user/$id')({
  loader: ({ params }) => {
    // do not await this nor return the promise, just kick off the query to stream it to the client
    context.queryClient.fetchQuery(userQuery(params.id))
  },
})
import { createFileRoute } from '@tanstack/react-router'
import { queryOptions, useQuery } from '@tanstack/react-query'

const userQuery = (id: string) =>
  queryOptions({
    queryKey: ['user', id],
    queryFn: () => fetch(`/api/users/${id}`).then((r) => r.json()),
  })

export const Route = createFileRoute('/user/$id')({
  loader: ({ params }) => {
    // do not await this nor return the promise, just kick off the query to stream it to the client
    context.queryClient.fetchQuery(userQuery(params.id))
  },
})

Redirect-Handling

Wenn eine Query oder Mutation einen redirect(...) wirft, fängt die Integration ihn auf dem Client ab und führt eine Router-Navigation durch.

  • Standardmäßig aktiviert
  • Deaktivieren Sie mit handleRedirects: false, wenn Sie benutzerdefiniertes Handling benötigen

Funktioniert mit TanStack Start

TanStack Start verwendet TanStack Router unter der Haube. Die gleiche Einrichtung gilt, und die Integration streamt Query-Ergebnisse während SSR automatisch.

Unsere Partner
Code Rabbit
Netlify
Neon
Clerk
Convex
Sentry
Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.

Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.