Framework
Version
Integrationen

Verzögertes Laden von Daten

TanStack Router ist so konzipiert, dass Loader parallel ausgeführt werden und darauf gewartet wird, bis alle aufgelöst sind, bevor die nächste Route gerendert wird. Das ist meistens großartig, aber gelegentlich möchten Sie dem Benutzer vielleicht früher etwas anzeigen, während die restlichen Daten im Hintergrund geladen werden.

Verzögertes Laden von Daten ist ein Muster, das es dem Router ermöglicht, kritische Daten/Markup des nächsten Speicherorts zu rendern, während langsamere, nicht kritische Routendaten im Hintergrund aufgelöst werden. Dieser Prozess funktioniert sowohl auf dem Client als auch auf dem Server (per Streaming) und ist eine großartige Möglichkeit, die gefühlte Leistung Ihrer Anwendung zu verbessern.

Wenn Sie eine Bibliothek wie TanStack Query oder eine andere Datenabrufbibliothek verwenden, funktioniert das verzögerte Laden von Daten etwas anders. Springen Sie zum Abschnitt Verzögertes Laden von Daten mit externen Bibliotheken für weitere Informationen.

Verzögertes Laden von Daten mit Await

Um langsame oder nicht kritische Daten zu verzögern, geben Sie ein nicht erwartetes/nicht aufgelöstes Promise irgendwo in Ihrer Loader-Antwort zurück

tsx
// src/routes/posts.$postId.tsx
import { createFileRoute, defer } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/$postId')({
  loader: async () => {
    // Fetch some slower data, but do not await it
    const slowDataPromise = fetchSlowData()

    // Fetch and await some data that resolves quickly
    const fastData = await fetchFastData()

    return {
      fastData,
      deferredSlowData: slowDataPromise,
    }
  },
})
// src/routes/posts.$postId.tsx
import { createFileRoute, defer } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/$postId')({
  loader: async () => {
    // Fetch some slower data, but do not await it
    const slowDataPromise = fetchSlowData()

    // Fetch and await some data that resolves quickly
    const fastData = await fetchFastData()

    return {
      fastData,
      deferredSlowData: slowDataPromise,
    }
  },
})

Sobald irgendein erwartetes Promise aufgelöst ist, beginnt die nächste Route mit dem Rendern, während die verzögerten Promises weiterhin aufgelöst werden.

In der Komponente können verzögerte Promises mit der Komponente Await aufgelöst und verwendet werden.

tsx
// src/routes/posts.$postId.tsx
import { createFileRoute, Await } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/$postId')({
  // ...
  component: PostIdComponent,
})

function PostIdComponent() {
  const { deferredSlowData, fastData } = Route.useLoaderData()

  // do something with fastData

  return (
    <Await promise={deferredSlowData} fallback={<div>Loading...</div>}>
      {(data) => {
        return <div>{data}</div>
      }}
    </Await>
  )
}
// src/routes/posts.$postId.tsx
import { createFileRoute, Await } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/$postId')({
  // ...
  component: PostIdComponent,
})

function PostIdComponent() {
  const { deferredSlowData, fastData } = Route.useLoaderData()

  // do something with fastData

  return (
    <Await promise={deferredSlowData} fallback={<div>Loading...</div>}>
      {(data) => {
        return <div>{data}</div>
      }}
    </Await>
  )
}

Tipp

Wenn Ihre Komponente Code-Split ist, können Sie die Funktion getRouteApi verwenden, um den Import der Route-Konfiguration zu vermeiden und so Zugriff auf den typisierten Hook useLoaderData() zu erhalten.

Die Komponente Await löst das Promise aus, indem sie die nächste Suspense-Grenze auslöst, bis es aufgelöst ist. Danach rendert sie die children der Komponente als Funktion mit den aufgelösten Daten.

Wenn das Promise abgelehnt wird, löst die Komponente Await den serialisierten Fehler aus, der von der nächsten Fehlergrenze abgefangen werden kann.

Tipp

In React 19 können Sie den Hook use() anstelle von Await verwenden.

Verzögertes Laden von Daten mit externen Bibliotheken

Wenn Ihre Strategie zum Abrufen von Informationen für die Route auf externem Datenladen mit einer externen Bibliothek wie TanStack Query beruht, funktioniert das verzögerte Laden von Daten etwas anders, da die Bibliothek das Datenabrufen und Caching für Sie außerhalb von TanStack Router übernimmt.

Anstatt also defer und Await zu verwenden, möchten Sie stattdessen den loader der Route verwenden, um den Datenabruf zu starten, und dann die Hooks der Bibliothek verwenden, um in Ihren Komponenten auf die Daten zuzugreifen.

tsx
// src/routes/posts.$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
import { slowDataOptions, fastDataOptions } from '~/api/query-options'

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ context: { queryClient } }) => {
    // Kick off the fetching of some slower data, but do not await it
    queryClient.prefetchQuery(slowDataOptions())

    // Fetch and await some data that resolves quickly
    await queryClient.ensureQueryData(fastDataOptions())
  },
})
// src/routes/posts.$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
import { slowDataOptions, fastDataOptions } from '~/api/query-options'

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ context: { queryClient } }) => {
    // Kick off the fetching of some slower data, but do not await it
    queryClient.prefetchQuery(slowDataOptions())

    // Fetch and await some data that resolves quickly
    await queryClient.ensureQueryData(fastDataOptions())
  },
})

Dann können Sie in Ihrer Komponente die Hooks der Bibliothek verwenden, um auf die Daten zuzugreifen

tsx
// src/routes/posts.$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
import { useSuspenseQuery } from '@tanstack/react-query'
import { slowDataOptions, fastDataOptions } from '~/api/query-options'

export const Route = createFileRoute('/posts/$postId')({
  // ...
  component: PostIdComponent,
})

function PostIdComponent() {
  const fastData = useSuspenseQuery(fastDataOptions())

  // do something with fastData

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <SlowDataComponent />
    </Suspense>
  )
}

function SlowDataComponent() {
  const data = useSuspenseQuery(slowDataOptions())

  return <div>{data}</div>
}
// src/routes/posts.$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
import { useSuspenseQuery } from '@tanstack/react-query'
import { slowDataOptions, fastDataOptions } from '~/api/query-options'

export const Route = createFileRoute('/posts/$postId')({
  // ...
  component: PostIdComponent,
})

function PostIdComponent() {
  const fastData = useSuspenseQuery(fastDataOptions())

  // do something with fastData

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <SlowDataComponent />
    </Suspense>
  )
}

function SlowDataComponent() {
  const data = useSuspenseQuery(slowDataOptions())

  return <div>{data}</div>
}

Caching und Invalidierung

Gestreamte Promises folgen dem gleichen Lebenszyklus wie die ihnen zugeordneten Loader-Daten. Sie können sogar vorab geladen werden!

SSR & Streaming von verzögerten Daten

Streaming erfordert einen Server, der es unterstützt, und dass TanStack Router korrekt dafür konfiguriert ist.

Bitte lesen Sie den vollständigen Leitfaden zu Streaming-SSR für Schritt-für-Schritt-Anweisungen, wie Sie Ihren Server für Streaming einrichten.

SSR Streaming Lebenszyklus

Das Folgende ist ein Überblick darüber, wie verzögertes Datenstreaming mit TanStack Router funktioniert

  • Server
    • Promises werden markiert und verfolgt, wenn sie von Routen-Loadern zurückgegeben werden
    • Alle Loader werden aufgelöst und alle verzögerten Promises werden serialisiert und in das HTML eingebettet
    • Die Route beginnt mit dem Rendern
    • Verzögerte Promises, die mit der Komponente <Await> gerendert werden, lösen Suspense-Grenzen aus und ermöglichen es dem Server, HTML bis zu diesem Punkt zu streamen
  • Client
    • Der Client empfängt das anfängliche HTML vom Server
    • <Await>-Komponenten pausieren mit Platzhalter-Promises, während sie auf die Auflösung ihrer Daten auf dem Server warten
  • Server
    • Wenn verzögerte Promises aufgelöst werden, werden ihre Ergebnisse (oder Fehler) serialisiert und über ein Inline-Skript-Tag an den Client gestreamt
    • Die aufgelösten <Await>-Komponenten und ihre Suspense-Grenzen werden aufgelöst und ihr resultierendes HTML wird zusammen mit ihren dehydrierten Daten an den Client gestreamt
  • Client
    • Die pausierten Platzhalter-Promises innerhalb von <Await> werden mit den gestreamten Daten/Fehlerantworten aufgelöst und rendern entweder das Ergebnis oder lösen den Fehler an die nächste Fehlergrenze aus
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.