Data Fetching in React und Next.js, verglichen an einer App
Data Fetching in React: Server, TanStack Query, SWR | We.Inc
Wähle mit einem kurzen Quiz einen Ansatz für Data Fetching in React und vergleiche dann Server Components, TanStack Query und SWR bei Caching, Mutationen und Standardwerten, an einer einzigen Beispiel-App.
Lade Daten auf dem Server, wann immer es geht: Im Next.js App Router wartet eine asynchrone Server Component auf die Daten, bevor überhaupt HTML gesendet wird, ganz ohne Code für Lade-Spinner. Für Daten, die sich ändern, während die Seite offen ist, nutze einen Client-Cache wie TanStack Query oder SWR, der Caching, Wiederholungen und Mutationen übernimmt. Ein einfaches fetch in useEffect passt für einmalige Anfragen.
Welcher Ansatz passt
Ansatz
Läuft wo
Caching
Am besten für
Asynchrone Server Component
Server
Standardmäßig nicht gecacht, aktivierbar mit use cache
Seitendaten, Secrets, Datenbankabfragen
TanStack Query
Browser
Query-Cache mit queryKey als Schlüssel
Dashboards, Mutationen, Paginierung
SWR
Browser
Cache mit dem Request-Schlüssel
Leselastige Ansichten, die aktuell bleiben sollen
useEffect + fetch
Browser
Keins, außer du schreibst es selbst
Eine kleine Anfrage in einer kleinen App
Jedes Beispiel auf dieser Seite lädt und bearbeitet dieselbe kleine Notizliste, damit die Unterschiede vom Ansatz kommen und nicht von der Demo. Beantworte die drei Fragen unten, um eine erste Empfehlung und das passende Snippet zu bekommen.
Gib an, ob du ein Framework mit Server Components nutzt, etwa den Next.js App Router.
Gib an, ob die Daten aktuell bleiben müssen, solange die Seite offen ist, und ob Nutzer sie bearbeiten.
Lies die Empfehlung und kopiere das passende Snippet.
Prüfe in den Vergleichsabschnitten unten die Standardwerte, bevor du live gehst.
Starte Anfragen gemeinsam. Zwei awaits hintereinander bilden einen Wasserfall: Erzeuge zuerst beide Promises und warte dann mit Promise.all.
Verwende bei jedem useQuery, das dieselben Daten liest, denselben queryKey, damit Komponenten sich eine Anfrage und einen Cache-Eintrag teilen.
Invalidiere nach einer Mutation den betroffenen Schlüssel, statt den Cache von Hand zu flicken, außer du brauchst ein sofortiges optimistisches Update.
Lade nie Secrets in einer Client Component. Alles, was der Browser anfragt, kann man im Netzwerk-Tab sehen.
Häufige Fragen
Werden fetch-Anfragen im Next.js App Router gecacht?
Laut aktueller Next.js-Dokumentation werden fetch-Anfragen standardmäßig nicht gecacht und blockieren das Rendern, bis sie fertig sind. Identische Anfragen innerhalb eines Renders werden memoisiert, und Caching aktivierst du mit der Direktive use cache, oder du streamst frische Daten innerhalb von Suspense.
Was sind die wichtigen Standardwerte von TanStack Query?
Daten sind sofort veraltet (staleTime 0), daher wird beim Mounten, beim Fokussieren des Fensters und bei erneuter Verbindung neu geladen. Ungenutzte Queries bleiben 5 Minuten im Speicher (gcTime), und fehlgeschlagene Queries werden 3 Mal mit exponentiellem Backoff wiederholt. Erhöhe staleTime, wenn dir dieses Nachladen zu viel ist.
TanStack Query oder SWR?
Beide cachen nach Schlüssel und validieren bei Fokus und erneuter Verbindung neu. TanStack Query bringt mehr Eingebautes für Mutationen, Invalidierung und Devtools mit, SWR hat eine kleinere API rund um useSWR(key, fetcher). Wähle eine Bibliothek pro App, beide zusammen verdoppeln den Cache.
Brauche ich mit Server Components noch eine Client-Bibliothek?
Für das Laden von Seiten oft nicht. Du brauchst eine, wenn Daten sich ohne Navigation aktualisieren müssen, wenn Nutzer bearbeiten und sofortiges Feedback erwarten, oder für unendliche Listen. Viele Apps laden auf dem Server und nutzen einen Client-Cache nur auf interaktiven Screens.
Wie prüfe ich mit Supabase auf dem Server, wer angemeldet ist?
Der serverseitige Leitfaden von Supabase sagt, dass man getSession() in Servercode nie vertrauen soll. Rufe supabase.auth.getClaims() auf, das die Signatur des Tokens prüft, und frage dann deine Tabellen ab. Row Level Security gilt weiterhin für jede Abfrage.
Zuerst der Server, dann bei Bedarf ein Client-Cache
Eine Server Component kann direkt mit Zugangsdaten eine Datenbank abfragen oder eine API aufrufen, und das Ergebnis kommt als HTML an. Das entfernt Ladezustands-Code aus den meisten Seiten und hält Schlüssel aus dem Browser-Bundle heraus.
Interaktive Screens sind anders. Eine Notizliste, die Leute ergänzen, filtern und erneut besuchen, profitiert von einem Client-Cache, der Ergebnisse zwischen Screens behält und im Hintergrund aktualisiert.
Streamen statt warten
Wenn eine Anfrage langsam ist, umschließe die Komponente, die sie braucht, mit Suspense und einem Fallback. Der Rest der Seite wird sofort gesendet, und der langsame Teil wird nachgestreamt. Eine loading.js-Datei macht dasselbe in Next.js für ein ganzes Routensegment.
In einer Client Component kannst du auch ein Promise vom Server entgegennehmen und es mit der use-API von React innerhalb von Suspense lesen.
Warum das einfache useEffect-Muster nicht reicht
Ein fetch in useEffect hat keinen Cache, daher wiederholt jedes Mounten die Anfrage, und Race Conditions, Ladezustände und Fehler musst du von Hand behandeln. Für ein kleines Widget ist das in Ordnung. Für alles Größere liefert dir eine Bibliothek all das in wenigen Zeilen. Die Grundlagen von fetch selbst behandelt unser Leitfaden zu async und fetch.
Standardwerte, die Leute überraschen
Verhalten ohne Konfiguration
Verhalten
Next.js-Server-fetch
TanStack Query
SWR
Über Anfragen hinweg gecacht
Nein, aktivierbar mit use cache
Im Speicher, pro Browser-Tab
Im Speicher, pro Browser-Tab
Doppelte Anfragen
Innerhalb eines Renders memoisiert
Über queryKey geteilt
Innerhalb von 2 Sekunden nach Schlüssel dedupliziert
Neu laden bei Fensterfokus
Nicht zutreffend
Ja, wenn veraltet
Ja
Neu laden bei erneuter Verbindung
Nicht zutreffend
Ja, wenn veraltet
Ja
Wiederholungen bei Fehlern
Selbst behandeln
3, mit exponentiellem Backoff
Ja (errorRetryInterval 5000 ms)
Ungenutzte Daten behalten für
Nicht zutreffend
5 Minuten (gcTime)
Kein dokumentierter Standardwert
Wasserfälle auf dem Server vermeiden
Beide Anfragen starten, dann gemeinsam abwarten
Wenn du beide Funktionen aufrufst, bevor du wartest, wartet keine auf die andere.
Einen langsamen Teil mit Suspense streamen
Die Überschrift wird sofort gesendet, die Notizliste wird nachgestreamt, sobald ihre Daten ankommen.
Supabase in einer Server Component
Hier wird der createClient-Helper aus dem serverseitigen Next.js-Leitfaden von Supabase verwendet (lib/supabase/server.ts, basierend auf @supabase/ssr). getClaims() prüft das Token des angemeldeten Nutzers, bevor die Abfrage läuft.
Notizen des angemeldeten Nutzers, auf dem Server geladen
Row Level Security auf der Tabelle notes entscheidet, welche Zeilen zurückkommen.
Wähle einen Ansatz
Nutzt du Server Components (zum Beispiel den Next.js App Router)?
Müssen sich die Daten aktualisieren, während die Seite offen bleibt?
Bearbeiten Nutzer diese Daten auf dem Screen?
Ja
Nein
Start-Snippet
Snippet kopieren
Lade die Daten in einer asynchronen Server Component. Ergänze später nur für die Teile, die interaktiv werden, einen Client-Cache.
Nutze TanStack Query: useQuery zum Lesen, useMutation zum Schreiben und invalidateQueries zum Aktualisieren nach einer Änderung.
Nutze SWR: useSWR hält die Ansicht bei Fokus und erneuter Verbindung mit sehr wenig Code aktuell.
Ein einzelnes fetch in useEffect reicht hier. Räume mit einem ignore-Flag auf, damit eine verspätete Antwort keinen neueren State überschreibt.