Nuxt useFetch vs. useAsyncData: Wann welches Composable die richtige Wahl ist
AI generated
{ }
Nuxt 3 · Data Fetching · Composables
Nuxt useFetch vs. useAsyncData im Detail
Wann welches Composable die richtige Wahl für den Datenabruf ist

useFetch ist im Kern ein Convenience-Wrapper um useAsyncData in Kombination mit $fetch. Sobald eigene Transform-Funktionen, präzise Caching-Keys oder eine komplexere Datenquelle jenseits eines einfachen HTTP-Requests ins Spiel kommen, ist der direkte Griff zu useAsyncData meist die klarere Wahl.

15 Min. Lesezeit useFetch · useAsyncData Nuxt 3 Data Fetching

1. Das Grundproblem: Daten laden in einer SSR-Anwendung

In einer serverseitig gerenderten Nuxt-Anwendung muss ein Datenabruf sowohl auf dem Server als auch im Browser korrekt funktionieren, ohne dass die Daten doppelt geladen werden. Würde man einfach ein normales fetch in einem onMounted-Hook aufrufen, gäbe es beim initialen Rendern keine Daten auf dem Server, und der Nutzer sähe kurzzeitig einen leeren Zustand, bevor der Browser die Daten nachlädt.

Nuxt löst dieses Problem durch spezielle Daten-Composables, die den Zustand eines asynchronen Abrufs automatisch zwischen Server und Client synchronisieren. Der Server führt den Abruf aus, serialisiert das Ergebnis in den initialen HTML-Payload, und der Client übernimmt dieses Ergebnis bei der Hydration, ohne den Request ein zweites Mal auszuführen. Genau hier setzen sowohl useFetch als auch useAsyncData an.

2. useFetch als Convenience-Wrapper

useFetch(url, options) kombiniert intern useAsyncData mit $fetch und generiert dabei automatisch einen sinnvollen Caching-Key aus der URL und den übergebenen Optionen. Für den häufigsten Fall, nämlich das direkte Laden von Daten von einem bekannten Endpunkt, spart das Boilerplate-Code, da weder ein eigener Key noch eine eigene Handler-Funktion geschrieben werden muss.

Die Rückgabewerte von useFetch entsprechen denen von useAsyncData: data, pending, error und refresh stehen als reaktive Werte zur Verfügung. Zusätzlich unterstützt useFetch dieselben Optionen wie $fetch direkt, etwa method, query oder headers, was die Definition eines typischen GET- oder POST-Requests sehr kompakt macht.

3. useAsyncData mit eigener Transform-Funktion

useAsyncData(key, handler, options) ist das flexiblere, allgemeinere der beiden Composables. Der handler ist eine beliebige asynchrone Funktion, die nicht zwingend einen HTTP-Request ausführen muss, sie kann auch mehrere Requests kombinieren, Daten aus einer Datenbank lesen oder eine komplexe Berechnung durchführen. Der key wird explizit angegeben und steuert, unter welchem Bezeichner das Ergebnis im Nuxt-Payload zwischengespeichert wird.

Besonders nützlich ist die transform-Option, mit der sich die Rohantwort direkt nach dem Abruf in eine passendere Form bringen lässt, etwa um nur benötigte Felder herauszufiltern oder mehrere Endpunkte zu einem gemeinsamen Ergebnisobjekt zusammenzuführen. Dadurch bleibt das gespeicherte Payload kleiner und die Komponente arbeitet direkt mit der gewünschten Datenstruktur.


// useFetch: kompakt für den Standardfall
const { data: product, pending, error } = await useFetch(
  `/api/products/${id}`,
  { key: `product-${id}` }
);

// useAsyncData: volle Kontrolle über Handler und Transform
const { data: summary } = await useAsyncData(
  `product-summary-${id}`,
  async () => {
    const [product, reviews] = await Promise.all([
      $fetch(`/api/products/${id}`),
      $fetch(`/api/products/${id}/reviews`),
    ]);
    return { product, averageRating: reviews.average };
  },
  {
    transform: (data) => ({
      title: data.product.title,
      rating: data.averageRating,
    }),
  }
);

4. Caching-Keys im Detail

Der Caching-Key bestimmt, unter welchem Eintrag im Nuxt-Payload ein Ergebnis abgelegt wird, und er entscheidet damit auch darüber, ob zwei Aufrufe an derselben Stelle im Code dasselbe zwischengespeicherte Ergebnis teilen. Bei useFetch wird der Key automatisch aus URL, Methode und Body generiert, was in den meisten Fällen ausreichend eindeutig ist, aber bei dynamisch generierten URLs mit komplexen Query-Parametern nicht immer optimal funktioniert.

Bei useAsyncData muss der Key explizit vergeben werden, was zunächst mehr Schreibarbeit bedeutet, aber auch präzise Kontrolle ermöglicht. Ein häufiges Muster ist, den Key aus einer Kombination von Routennamen und relevanten Parametern zusammenzusetzen, etwa `product-${id}-${locale}`, um sicherzustellen, dass unterschiedliche Sprachversionen oder Varianten nicht versehentlich denselben zwischengespeicherten Wert teilen.

5. Entscheidungskriterien: Wann welches Composable?

Für einen einfachen, direkten Abruf von einem einzelnen REST-Endpunkt, bei dem die Rohantwort direkt verwendet werden kann, ist useFetch in aller Regel die kürzere und lesbarere Wahl. Der automatisch generierte Key und die direkte Übernahme der $fetch-Optionen reduzieren den Code auf das Wesentliche, ohne dass dabei Funktionalität verloren geht.

Sobald mehrere Requests kombiniert werden müssen, eine eigene Transform-Logik nötig ist, die Datenquelle kein einfacher HTTP-Aufruf ist, oder der Caching-Key aus gutem Grund manuell kontrolliert werden soll, ist useAsyncData die passendere Wahl. Als Faustregel gilt: useFetch für den einfachen Fall, useAsyncData für alles, was darüber hinausgeht.

6. Häufige Fallstricke bei doppeltem Datenabruf

Ein sehr häufiger Fehler besteht darin, Daten zusätzlich zu useFetch oder useAsyncData noch einmal in einem onMounted-Hook per direktem $fetch-Aufruf zu laden. Das führt dazu, dass der Request tatsächlich zweimal ausgeführt wird, einmal serverseitig über das Composable und einmal zusätzlich im Browser, was unnötige Serverlast und ein kurzzeitig inkonsistentes UI erzeugt.

Ein zweiter häufiger Fallstrick betrifft fehlende oder falsch gesetzte Keys bei dynamischen Routen: Verwendet man denselben, statischen Key für eine Komponente, die auf verschiedenen Detailseiten mit unterschiedlichen IDs wiederverwendet wird, liefert Nuxt beim Navigieren zwischen zwei Detailseiten fälschlicherweise die zwischengespeicherten, alten Daten zurück, statt einen neuen Request auszulösen. Der Key muss deshalb immer die relevanten, variablen Parameter enthalten.

7. Verhalten zwischen Server und Client

Standardmäßig führen beide Composables den Abruf während des Server-Side Renderings aus und übertragen das Ergebnis als Teil des initialen Payloads an den Client. Bei der Hydration im Browser erkennt Nuxt anhand des Keys, dass für diesen Abruf bereits ein Ergebnis vorliegt, und führt den Request nicht erneut aus, sofern server und lazy nicht explizit anders konfiguriert wurden.

Mit der Option server: false lässt sich ein Abruf gezielt auf den Client beschränken, was etwa für Daten sinnvoll ist, die nur im Browser verfügbare Informationen wie localStorage benötigen. Die Option lazy: true wiederum verzögert das Rendering nicht auf das Ergebnis des Abrufs, sondern zeigt die Komponente sofort mit pending: true an und aktualisiert sie, sobald die Daten eintreffen.

8. Die watch-Option: Auf reaktive Parameter reagieren

Hängt ein Abruf von einem reaktiven Wert ab, etwa einer per ref gehaltenen Sortierreihenfolge oder einem Suchbegriff aus einem Eingabefeld, soll der Request idealerweise automatisch neu ausgeführt werden, sobald sich dieser Wert ändert. Beide Composables unterstützen dafür die watch-Option, der eine Liste reaktiver Quellen übergeben wird, deren Änderung einen erneuten Abruf auslöst.

Ohne explizit gesetzte watch-Option reagiert weder useFetch noch useAsyncData automatisch auf Änderungen an Variablen, die innerhalb des Handlers oder der URL verwendet werden, selbst wenn diese Variablen reaktiv sind. Wird dieser Zusammenhang übersehen, bleibt eine Liste nach einer Suchbegriffsänderung fälschlicherweise unverändert stehen, bis die Seite manuell neu geladen wird, was in der Praxis zu einem der verwirrendsten Fehlerbilder bei diesen Composables zählt.

9. Fazit: Zwei Werkzeuge für denselben Zweck

useFetch und useAsyncData lösen dasselbe grundlegende Problem des synchronisierten Datenabrufs zwischen Server und Client, unterscheiden sich aber deutlich im Grad der Kontrolle, den sie bieten. Wer die Wahl bewusst nach der tatsächlichen Komplexität des Anwendungsfalls trifft, statt reflexhaft immer dasselbe Composable zu verwenden, schreibt tendenziell kürzeren und gleichzeitig korrekteren Code.

Besonders wichtig bleibt in beiden Fällen ein durchdachter Caching-Key sowie der bewusste Verzicht auf zusätzliche, manuelle Fetch-Aufrufe außerhalb der Composables. Wer diese beiden Grundregeln beachtet, vermeidet die häufigsten Performance- und Konsistenzprobleme beim Datenabruf in Nuxt-Anwendungen zuverlässig.

Aspekt useFetch useAsyncData
Caching-Key Automatisch aus URL/Optionen generiert Muss explizit angegeben werden
Datenquelle Direkter $fetch-Request Beliebige asynchrone Handler-Funktion
Transform-Option Vorhanden, über Options-Objekt Vorhanden, volle Kontrolle im Handler
Code-Umfang Kompakt für Standardfälle Etwas mehr Code, mehr Flexibilität
Typischer Einsatz Einzelner REST-Endpunkt Kombinierte Requests, komplexe Logik

Mironsoft

Vue-Architektur, Composition API und Nuxt-Performance

Vue-Anwendungen, die mit jedem Feature nicht komplizierter werden?

Wir prüfen bestehende Vue- und Nuxt-Projekte auf unstrukturierte Composables, ungenutzte Reaktivität und aufgeblähte Bundles und bauen daraus eine Architektur, die neue Features aufnimmt, ohne die Codebasis unübersichtlicher zu machen.

Architektur-Review

Composables, State-Management und Komponentenstruktur auf Wartbarkeit prüfen.

Performance-Audit

Reaktivitäts-Overhead, Bundle-Größe und Nuxt-Rendering-Strategie systematisch optimieren.

Nuxt-Integration

SSR/SSG-Setup und API-Anbindung robust und typsicher aufbauen.

10. Zusammenfassung

useFetch vs. useAsyncData: Das Wichtigste auf einen Blick

useFetch

Convenience-Wrapper um useAsyncData plus $fetch für den Standardfall

useAsyncData

Volle Kontrolle über Handler, Transform-Funktion und Caching-Key

Häufigster Fehler

Zusätzlicher manueller Fetch in onMounted führt zu doppeltem Abruf

Faustregel

useFetch für einfache Endpunkte, useAsyncData für alles Komplexere

11. FAQ: useFetch vs. useAsyncData: Das Wichtigste auf einen Blick

1Ist useFetch langsamer als useAsyncData?
Nein, useFetch ruft intern genau dieselben Mechanismen wie useAsyncData auf, es handelt sich lediglich um eine Komfort-Schicht darüber. Die Performance beider Composables ist identisch, der Unterschied liegt ausschließlich in der Entwicklerergonomie.
2Kann ich useFetch für POST-Requests verwenden?
Ja, useFetch unterstützt dieselben Optionen wie $fetch direkt, darunter method, body und headers, wodurch sich auch POST-, PUT- oder DELETE-Requests kompakt formulieren lassen.
3Warum bekomme ich beim Navigieren zwischen zwei Detailseiten veraltete Daten?
Das passiert meist, weil der Caching-Key nicht die relevanten, variablen Parameter wie die ID enthält. Ohne einen eindeutigen Key pro Datensatz liefert Nuxt das zwischengespeicherte Ergebnis der vorherigen Seite zurück.
4Was bewirkt die Option lazy bei beiden Composables?
Mit lazy: true wartet das Rendering der Komponente nicht auf das Ergebnis des Abrufs, sondern zeigt sie sofort mit pending: true an und aktualisiert sie, sobald die Daten eintreffen, was für nicht kritische Inhalte oft die bessere Nutzererfahrung bietet.
5Muss ich den Datenabruf manuell im onMounted-Hook wiederholen?
Nein, das ist einer der häufigsten Fehler. Beide Composables kümmern sich bereits um die korrekte Synchronisation zwischen Server und Client, ein zusätzlicher manueller Aufruf führt lediglich zu einem doppelten Request.
6Wie funktioniert die transform-Option?
Die transform-Funktion erhält die Rohantwort des Abrufs und gibt eine beliebig umgeformte Version davon zurück. Das gespeicherte Ergebnis im Payload entspricht dann bereits der transformierten Form, nicht der ursprünglichen Rohantwort.
7Kann ich mit useAsyncData mehrere Requests parallel ausführen?
Ja, der Handler von useAsyncData ist eine beliebige asynchrone Funktion, in der sich mehrere Requests problemlos mit Promise.all parallel ausführen und zu einem gemeinsamen Ergebnis zusammenführen lassen.
8Was passiert bei einem Fehler während des Abrufs?
Beide Composables liefern einen reaktiven error-Wert zurück, der im Fehlerfall das aufgetretene Problem enthält, während data auf null oder undefined bleibt. Die Komponente kann anhand von error gezielt eine Fehlermeldung anzeigen.
9Wie kann ich einen Abruf manuell erneut auslösen?
Beide Composables geben eine refresh-Funktion zurück, die den zugrunde liegenden Abruf erneut ausführt und das gespeicherte Ergebnis unter demselben Key aktualisiert, etwa nach einer Nutzeraktion wie einem Klick auf Aktualisieren.
10Sollte ich immer einen expliziten Key angeben, auch bei useFetch?
Bei einfachen, statischen URLs ist der automatisch generierte Key meist ausreichend. Bei dynamischen URLs mit komplexen Query-Parametern oder wiederverwendeten Komponenten empfiehlt es sich, den Key über die key-Option explizit selbst zu setzen.