Wer in React-Anwendungen Daten von einer API laden möchte, stand lange vor einer Entscheidung: Entweder wird der State manuell mit useEffect und useState verwaltet – mit all den Fallen rund um Race Conditions, Ladezustände und Cache-Management – oder es wird ein globales State-Management-Tool wie Redux bemüht, das für diesen Anwendungsfall schlicht überdimensioniert ist. TanStack Query, früher bekannt als React Query, hat dieses Problem grundlegend gelöst.
Was ist TanStack Query?
TanStack Query ist eine Bibliothek für das asynchrone State-Management in React und anderen JavaScript-Frameworks. Die Kernidee: Server-seitiger State – also Daten, die von einer API kommen – unterscheidet sich grundlegend von Client-seitigem State wie Formularwerten oder UI-Zuständen. Server-State kann sich ändern ohne das Wissen des Clients, er ist asynchron und muss regelmäßig synchronisiert werden.
TanStack Query übernimmt genau diese Komplexität: Caching, Background-Refetching, Fehlerbehandlung, Ladezustände und Deduplizierung von Anfragen – alles out of the box, ohne eine einzige Zeile manuellen Cache-Managements.
Die Bibliothek unterstützt neben React auch Vue, Solid, Svelte und Angular. Das GitHub-Repository zählt über 45.000 Stars und ist damit eines der einflussreichsten Projekte im React-Ökosystem.
Stale-While-Revalidate-Strategie
Das zentrale Konzept hinter TanStack Query ist die Stale-While-Revalidate-Strategie. Dabei wird gecachte Daten sofort an die Komponente zurückgegeben (auch wenn sie "veraltet" sind), während gleichzeitig im Hintergrund eine neue Anfrage gestellt wird. Sobald die frischen Daten ankommen, wird die Komponente automatisch neu gerendert.
Diese Strategie führt zu zwei wichtigen Vorteilen: Die Benutzeroberfläche zeigt niemals unnötige Ladeindikatoren für Daten, die bereits gecacht sind, und gleichzeitig sind die angezeigten Daten immer möglichst aktuell. Das Ergebnis ist eine deutlich flüssigere Benutzererfahrung im Vergleich zu klassischen Loading-Spinner-Ansätzen.
useQuery: Daten laden
Der grundlegende Hook zum Abrufen von Daten ist useQuery:
import { useQuery } from '@tanstack/react-query';
function NutzerProfil({ nutzerId }) {
const { data, isLoading, isError, error } = useQuery({
queryKey: ['nutzer', nutzerId],
queryFn: () => fetch(`/api/nutzer/${nutzerId}`).then(r => r.json()),
staleTime: 5 * 60 * 1000, // 5 Minuten
});
if (isLoading) return <Ladeanzeige />;
if (isError) return <Fehlermeldung error={error} />;
return <div>{data.name}</div>;
}
Das queryKey-Array ist der Cache-Schlüssel. Wenn sich ein Teil des Schlüssels ändert (z.B. die nutzerId), wird automatisch eine neue Anfrage gestellt. Mehrere Komponenten, die denselben queryKey verwenden, teilen sich den gleichen Cache-Eintrag – die API wird nur einmal aufgerufen.
useMutation: Daten verändern
Für schreibende Operationen steht useMutation bereit:
import { useMutation, useQueryClient } from '@tanstack/react-query';
function NutzerBearbeiten({ nutzerId }) {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (neuerName) =>
fetch(`/api/nutzer/${nutzerId}`, {
method: 'PATCH',
body: JSON.stringify({ name: neuerName }),
}).then(r => r.json()),
onSuccess: () => {
// Cache für diesen Nutzer invalidieren
queryClient.invalidateQueries({ queryKey: ['nutzer', nutzerId] });
},
});
return (
<button onClick={() => mutation.mutate('Max Mustermann')}>
{mutation.isPending ? 'Wird gespeichert…' : 'Speichern'}
</button>
);
}
QueryKey-Caching und Invalidierung
TanStack Query verwaltet einen In-Memory-Cache aller abgerufenen Daten. Jeder Cache-Eintrag wird durch seinen queryKey identifiziert. Der QueryClient bietet Methoden zur Steuerung dieses Caches:
invalidateQueries()markiert einen oder mehrere Cache-Einträge als veraltet und löst ein Re-fetch aussetQueryData()setzt Cache-Daten manuell, ohne eine API-Anfrage zu stellenprefetchQuery()lädt Daten proaktiv in den Cache, bevor sie benötigt werdenremoveQueries()entfernt Cache-Einträge vollständig
Background-Refetching
TanStack Query führt automatisch Re-Fetches in mehreren Situationen durch:
- Wenn das Browser-Fenster wieder fokussiert wird (Window Focus Refetching)
- Wenn die Netzwerkverbindung nach einem Ausfall wiederhergestellt wird
- In konfigurierbaren Intervallen mit
refetchInterval - Wenn der
queryKeyeiner gemounteten Komponente sich ändert
All diese Verhaltensweisen lassen sich pro Query oder global konfigurieren. Für Daten, die sich selten ändern (z.B. eine Liste von Ländern), kann staleTime: Infinity gesetzt werden, um Re-Fetches zu deaktivieren.
queryKey-Arrays hierarchisch: ['nutzer'] als Basis, ['nutzer', 'liste'] für Listen und ['nutzer', nutzerId] für einzelne Einträge. Mit invalidateQueries({ queryKey: ['nutzer'] }) können dann alle nutzer-bezogenen Queries auf einmal invalidiert werden.
Optimistische Updates
Optimistische Updates erlauben es, die UI bereits vor der API-Antwort zu aktualisieren, um eine responsivere Benutzererfahrung zu erzielen. Bei einem Fehler wird der vorherige Zustand automatisch wiederhergestellt:
const mutation = useMutation({
mutationFn: updateNutzer,
onMutate: async (neuerNutzer) => {
await queryClient.cancelQueries({ queryKey: ['nutzer', neuerNutzer.id] });
const vorheriger = queryClient.getQueryData(['nutzer', neuerNutzer.id]);
queryClient.setQueryData(['nutzer', neuerNutzer.id], neuerNutzer);
return { vorheriger };
},
onError: (err, neuerNutzer, context) => {
queryClient.setQueryData(
['nutzer', neuerNutzer.id],
context.vorheriger
);
},
onSettled: (nutzer) => {
queryClient.invalidateQueries({ queryKey: ['nutzer', nutzer.id] });
},
});
DevTools
TanStack Query bietet offizielle DevTools, die als React-Komponente in die Applikation eingebunden werden. Sie zeigen alle aktiven Queries, deren Status, Daten und Cache-Zeitstempel in einem übersichtlichen Panel. Im Produktionsbuild können die DevTools einfach ausgelassen werden:
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
// In der App-Komponente:
{process.env.NODE_ENV === 'development' && (
<ReactQueryDevtools initialIsOpen={false} />
)}
Vergleich: TanStack Query vs. SWR vs. RTK Query vs. Apollo Client
| Merkmal | TanStack Query | SWR | RTK Query | Apollo Client |
|---|---|---|---|---|
| Bundle-Größe (min+gz) | ~13 kB | ~5 kB | ~10 kB (Teil von RTK) | ~33 kB |
| Framework-Support | React, Vue, Solid, Svelte, Angular | React | React (via Redux) | React, Vue, Angular |
| Optimistische Updates | Ja (vollständig) | Ja (einfacher) | Ja (vollständig) | Ja (vollständig) |
| Mutations | useMutation (erstklassig) | Manuell via useSWRMutation | Erstklassig | useMutation (GraphQL) |
| DevTools | Offiziell, sehr gut | Keine offiziellen | Redux DevTools | Apollo DevTools (Browser Extension) |
| API-Protokoll | Agnostisch (REST, GraphQL, etc.) | Agnostisch | REST-optimiert | GraphQL-only |
| Infinite Scroll / Pagination | useInfiniteQuery (eingebaut) | useSWRInfinite | Eingebaut | fetchMore |
useState, useReducer oder leichtgewichtige Stores wie Zustand. Der Versuch, alles in TanStack Query zu verwalten, führt zu unnötiger Komplexität.
Einrichtung
TanStack Query wird über npm installiert und erfordert einen QueryClientProvider an der Wurzel der Applikation:
npm install @tanstack/react-query
// main.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById('root')).render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
Die vollständige Dokumentation aller Hooks, Optionen und Muster findet sich in der offiziellen TanStack Query Dokumentation.
Häufig gestellte Fragen
- Brauche ich noch Redux, wenn ich TanStack Query verwende?
- In den meisten Fällen nicht mehr für Server-State. TanStack Query übernimmt das gesamte Caching und die Synchronisation von API-Daten. Für komplexen globalen Client-State (z.B. mehrstufige Wizard-Formulare, Shopping-Cart-Logik) können Redux oder alternative Stores wie Zustand weiterhin sinnvoll sein.
- Wie lange bleiben Daten im Cache?
- Standardmäßig werden Daten 5 Minuten nach dem letzten Abonnement im Cache behalten (gcTime). Daten gelten nach 0 Millisekunden als "stale" (veraltet), was bedeutet, dass bei jedem Mount ein Re-fetch ausgelöst wird. Beide Werte lassen sich global und pro Query anpassen.
- Funktioniert TanStack Query mit Server Components in Next.js?
- TanStack Query ist eine Client-seitige Bibliothek und funktioniert in React Client Components. Mit dem Hydration-Konzept lassen sich Queries jedoch serverseitig prefetchen und der Cache-Zustand an den Client übertragen, was die Kombination mit Next.js App Router ermöglicht. Die Dokumentation enthält eine ausführliche Next.js-Anleitung.
- Kann TanStack Query auch für Nicht-HTTP-Datenquellen verwendet werden?
- Ja. Die
queryFnkann jede asynchrone Funktion sein – IndexedDB-Zugriffe, WebSocket-Daten, lokale Berechnungen oder Datenbankabfragen in Electron-Apps. TanStack Query ist vollständig protokoll-agnostisch und verhält sich immer gleich, unabhängig von der Datenquelle.