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.
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
// 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.
// 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.
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.
// 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
// 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>
}
Gestreamte Promises folgen dem gleichen Lebenszyklus wie die ihnen zugeordneten Loader-Daten. Sie können sogar vorab geladen werden!
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.
Das Folgende ist ein Überblick darüber, wie verzögertes Datenstreaming mit TanStack Router funktioniert
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.