Server-seitiges Datenabrufen in Nuxt
Wenn Sie eine Nuxt-Anwendung entwickeln und sich fragen, warum Ihre Daten zweimal abgerufen werden – oder warum sich Komponenten, die denselben Key verwenden, unerwartet verhalten – sind Sie nicht allein. Das SSR-Datenabrufen in Nuxt folgt spezifischen Regeln, die selbst erfahrene Entwickler ins Stolpern bringen.
Dieser Artikel erklärt, wie useAsyncData und useFetch in Nuxt 4 funktionieren, und behandelt Payload-Hydration, Navigationsverhalten, Key-Verwaltung sowie die Fallstricke, die am meisten Verwirrung stiften.
Wichtigste Erkenntnisse
- Nuxt führt
useFetchunduseAsyncDataauf dem Server aus, serialisiert die Antworten in das HTML-Payload und hydratisiert auf dem Client ohne erneuten Abruf - Komponenten, die denselben Key verwenden, teilen sich identischen reaktiven State – verwenden Sie unterschiedliche Keys für unabhängige Dateninstanzen
- In aktuellen Nuxt-4-Releases müssen bestimmte Optionen (handler, transform, pick, getCachedData, default, deep) bei Aufrufen, die sich einen Key teilen, übereinstimmen
- Verwenden Sie
useFetchoderuseAsyncDatafür SSR-sicheres Abrufen; reservieren Sie$fetchfür Event-Handler und Client-only-Code
Wie Nuxt server-seitiges Datenabrufen ausführt
Wenn Sie useFetch oder useAsyncData in einer Page oder Komponente aufrufen, führt Nuxt diesen Abruf während der initialen Anfrage auf dem Server aus. Der Server serialisiert die Antwort in ein Payload, das in das HTML eingebettet wird. Wenn der Client hydratisiert, liest er dieses Payload, anstatt erneut abzurufen – dadurch werden doppelte Netzwerkanfragen eliminiert.
const { data } = await useFetch('/api/products')
Diese einzelne Zeile wird auf dem Server ausgeführt, bettet das Ergebnis in die Seite ein und hydratisiert nahtlos auf dem Client. Kein doppeltes Abrufen. Kein Hydration-Mismatch.
Blockierendes vs. Lazy Fetching
Standardmäßig blockiert Nuxt die Navigation, bis das awaited Datenabrufen abgeschlossen ist. Dies stellt sicher, dass Ihre Seite mit bereits verfügbaren Daten gerendert wird.
Für client-seitige Navigation können Sie sich für Lazy Fetching entscheiden:
const { data, status } = useLazyFetch('/api/comments')
Beim Lazy Fetching blockiert die Navigation standardmäßig nicht, während der Abruf im Hintergrund läuft. Sie müssen den Ladezustand in Ihrem Template mit der status-Ref handhaben.
Nuxt Data-Fetching-Keys verstehen
Keys sind zentral dafür, wie Nuxt Anfragen cached und dedupliziert. Jeder useFetch-Aufruf verwendet die URL als Standard-Key. Bei useAsyncData geben Sie den Key explizit an oder lassen Nuxt einen deterministischen generieren.
Hier der kritische Punkt: Komponenten, die denselben Key verwenden, teilen sich denselben State. Dies umfasst die Refs data, error, status und pending.
// Komponente A
const { data } = await useAsyncData('users', () => $fetch('/api/users'))
// Komponente B - teilt sich den State mit Komponente A
const { data } = await useAsyncData('users', () => $fetch('/api/users'))
Beide Komponenten erhalten identische reaktive Refs. Ändern Sie eine, spiegelt sich dies in der anderen wider.
Regeln für Key-Konsistenz
In aktuellen Nuxt-4-Versionen erzwingt Nuxt Konsistenz für bestimmte Optionen, wenn mehrere Aufrufe sich einen Key teilen. Diese müssen übereinstimmen:
- Handler-Funktion
transform-Funktionpick-ArraygetCachedData-Funktiondefault-Wertdeep-Option
Diese können sicher unterschiedlich sein:
serverlazyimmediatededupewatch
Verstöße gegen die Konsistenz lösen Entwicklungswarnungen und unvorhersehbares Verhalten aus.
Discover how at OpenReplay.com.
Sichere Key-Strategien
Für routenspezifische Daten fügen Sie Routenparameter in Ihren Key ein:
const route = useRoute()
const { data } = await useAsyncData(
`product-${route.params.id}`,
() => $fetch(`/api/products/${route.params.id}`)
)
Für unabhängige Instanzen, die sich keinen State teilen sollen, verwenden Sie unterschiedliche Keys:
const { data: sidebar } = await useAsyncData('users-sidebar', fetchUsers)
const { data: main } = await useAsyncData('users-main', fetchUsers)
Nuxt Data-Caching und Dedupe-Verhalten
Nuxt dedupliziert automatisch gleichzeitige Anfragen mit übereinstimmenden Keys. Wenn drei Komponenten gleichzeitig denselben Key anfordern, wird nur eine Netzwerkanfrage ausgelöst.
Die dedupe-Option steuert das Refresh-Verhalten:
const { data, refresh } = await useFetch('/api/data', {
dedupe: 'cancel' // bricht ausstehende Anfragen ab, bevor eine neue gestartet wird
})
In Nuxt 4.2 und später ist die Unterstützung für Abbrüche deutlich verbessert. Wenn unterstützt, können veraltete Antworten von vorherigen Routen bei schneller Navigation abgebrochen oder ignoriert werden, wodurch das Risiko reduziert wird, dass kurzzeitig veraltete Daten erscheinen.
Weitere Details: https://nuxt.com/docs/api/composables/use-fetch
Häufige Fallstricke
Verwechslung von Nuxts useFetch mit anderen Bibliotheken
Nuxts useFetch ist nicht dasselbe wie useFetch von @vueuse/core oder ähnlichen Utilities. Die Nuxt-Version handhabt SSR-Payload-Hydration automatisch. Die Verwendung von useFetch einer anderen Bibliothek umgeht dies vollständig und verursacht doppeltes Abrufen und Hydration-Mismatches.
Verwendung von $fetch im Setup ohne useAsyncData
Der direkte Aufruf von $fetch in <script setup> läuft sowohl auf Server als auch Client:
// ❌ Ruft zweimal ab
const data = await $fetch('/api/users')
// ✅ Ruft einmal ab, hydratisiert korrekt
const { data } = await useFetch('/api/users')
Reservieren Sie $fetch für Event-Handler und Client-only-Interaktionen.
Wiederverwendung von Keys mit widersprüchlichen Optionen
Dies löst Warnungen und Bugs aus:
// ❌ Widersprüchliche deep-Optionen
await useAsyncData('users', fetchUsers, { deep: false })
await useAsyncData('users', fetchUsers, { deep: true })
Erwartung von Daten vor Hydration mit server: false
Wenn Sie server: false setzen, bleiben die Daten null, bis die Hydration abgeschlossen ist – selbst wenn Sie das Composable awaiten.
Fazit
Das Data-Fetching-Modell von Nuxt 4 basiert auf Server-Ausführung, Payload-Hydration und Key-basiertem Caching. Halten Sie Keys stabil und eindeutig pro Datenquelle. Stellen Sie Optionskonsistenz sicher, wenn Keys über Komponenten hinweg geteilt werden. Verwenden Sie useFetch oder useAsyncData für SSR-sicheres Abrufen und reservieren Sie $fetch für client-seitige Interaktionen.
Beherrschen Sie diese Patterns, und Sie vermeiden die Bugs beim doppelten Abrufen und State-Sharing, die die meisten Nuxt-Entwickler frustrieren.
FAQs
Dies passiert typischerweise, wenn Sie $fetch direkt im script setup verwenden, anstatt useFetch oder useAsyncData. Direkte $fetch-Aufrufe laufen sowohl auf Server als auch Client. Wrappen Sie Ihre Abrufe in useFetch oder useAsyncData, um Payload-Hydration zu nutzen, die einmal auf dem Server abruft und diese Daten auf dem Client wiederverwendet.
Verwenden Sie useFetch, wenn Sie direkt von einer URL abrufen – es handhabt Keys automatisch basierend auf der URL. Verwenden Sie useAsyncData, wenn Sie benutzerdefinierte Logik, mehrere kombinierte API-Aufrufe oder explizite Kontrolle über den Cache-Key benötigen. Beide bieten dieselben SSR-Hydration-Vorteile.
Komponenten, die denselben Key verwenden, teilen sich identischen reaktiven State. Um Daten unabhängig zu halten, verwenden Sie eindeutige Keys für jede Komponente. Verwenden Sie zum Beispiel users-sidebar und users-main anstelle von nur users, wenn zwei Komponenten denselben Endpoint abrufen, aber separaten State benötigen.
Die dedupe-Option steuert, wie Nuxt mehrere Refresh-Aufrufe handhabt. Das Setzen von dedupe auf cancel bricht jede ausstehende Anfrage ab, bevor eine neue gestartet wird. Dies hilft, Race Conditions bei schnellen Benutzerinteraktionen zu vermeiden und stellt sicher, dass neuere Antworten Vorrang haben, wenn Abbruch unterstützt wird.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.