Back

Récupération de données côté serveur dans Nuxt

Récupération de données côté serveur dans Nuxt

Si vous développez une application Nuxt et que vous vous demandez pourquoi vos données sont récupérées deux fois—ou pourquoi des composants partageant la même clé se comportent de manière inattendue—vous n’êtes pas seul. La récupération de données SSR dans Nuxt suit des règles spécifiques qui déstabilisent même les développeurs expérimentés.

Cet article explique le fonctionnement de useAsyncData et useFetch dans Nuxt 4, en couvrant l’hydratation du payload, le comportement de navigation, la gestion des clés et les pièges qui causent le plus de confusion.

Points clés à retenir

  • Nuxt exécute useFetch et useAsyncData sur le serveur, sérialise les réponses dans le payload HTML et hydrate côté client sans nouvelle récupération
  • Les composants partageant la même clé partagent un état réactif identique—utilisez des clés distinctes pour des instances de données indépendantes
  • Dans les versions actuelles de Nuxt 4, certaines options (handler, transform, pick, getCachedData, default, deep) doivent correspondre entre les appels partageant une clé
  • Utilisez useFetch ou useAsyncData pour une récupération compatible SSR ; réservez $fetch pour les gestionnaires d’événements et le code client uniquement

Comment Nuxt exécute la récupération de données côté serveur

Lorsque vous appelez useFetch ou useAsyncData dans une page ou un composant, Nuxt exécute cette récupération sur le serveur lors de la requête initiale. Le serveur sérialise la réponse dans un payload intégré au HTML. Lorsque le client s’hydrate, il lit ce payload au lieu de refaire la récupération—éliminant ainsi les requêtes réseau en double.

const { data } = await useFetch('/api/products')

Cette simple ligne s’exécute sur le serveur, intègre le résultat dans la page et s’hydrate de manière transparente côté client. Pas de double récupération. Pas de désynchronisation d’hydratation.

Récupération bloquante vs. lazy

Par défaut, Nuxt bloque la navigation jusqu’à ce que la récupération de données awaitée soit terminée. Cela garantit que votre page s’affiche avec les données déjà disponibles.

Pour la navigation côté client, vous pouvez opter pour une récupération lazy :

const { data, status } = useLazyFetch('/api/comments')

Avec la récupération lazy, la navigation ne bloque pas par défaut pendant que la récupération s’exécute en arrière-plan. Vous devrez gérer l’état de chargement dans votre template en utilisant la ref status.

Comprendre les clés de récupération de données Nuxt

Les clés sont au cœur de la façon dont Nuxt met en cache et déduplique les requêtes. Chaque appel useFetch utilise l’URL comme clé par défaut. Pour useAsyncData, vous fournissez la clé explicitement ou laissez Nuxt en générer une déterministe pour vous.

Voici la partie critique : les composants partageant la même clé partagent le même état. Cela inclut les refs data, error, status et pending.

// Composant A
const { data } = await useAsyncData('users', () => $fetch('/api/users'))

// Composant B - partage l'état avec le Composant A
const { data } = await useAsyncData('users', () => $fetch('/api/users'))

Les deux composants reçoivent des refs réactives identiques. Modifiez l’une, et l’autre la reflète.

Règles de cohérence des clés

Dans les versions actuelles de Nuxt 4, Nuxt impose la cohérence de certaines options lorsque plusieurs appels partagent une clé. Celles-ci doivent correspondre :

  • Fonction handler
  • Fonction transform
  • Tableau pick
  • Fonction getCachedData
  • Valeur default
  • Option deep

Celles-ci peuvent différer en toute sécurité :

  • server
  • lazy
  • immediate
  • dedupe
  • watch

Violer la cohérence déclenche des avertissements en développement et un comportement imprévisible.

Stratégies de clés sûres

Pour les données spécifiques à une route, incluez les paramètres de route dans votre clé :

const route = useRoute()
const { data } = await useAsyncData(
  `product-${route.params.id}`,
  () => $fetch(`/api/products/${route.params.id}`)
)

Pour des instances indépendantes qui ne doivent pas partager d’état, utilisez des clés distinctes :

const { data: sidebar } = await useAsyncData('users-sidebar', fetchUsers)
const { data: main } = await useAsyncData('users-main', fetchUsers)

Mise en cache et comportement de déduplication des données Nuxt

Nuxt déduplique automatiquement les requêtes concurrentes avec des clés correspondantes. Si trois composants demandent la même clé simultanément, une seule requête réseau est déclenchée.

L’option dedupe contrôle le comportement de rafraîchissement :

const { data, refresh } = await useFetch('/api/data', {
  dedupe: 'cancel' // annule les requêtes en attente avant d'en démarrer une nouvelle
})

Dans Nuxt 4.2 et versions ultérieures, la prise en charge de l’annulation est considérablement améliorée. Lorsqu’elle est prise en charge, les réponses obsolètes des routes précédentes peuvent être annulées ou ignorées lors d’une navigation rapide, réduisant le risque d’apparition brève de données obsolètes.

Plus de détails : https://nuxt.com/docs/api/composables/use-fetch

Pièges courants

Confondre le useFetch de Nuxt avec d’autres bibliothèques

Le useFetch de Nuxt n’est pas le même que celui de @vueuse/core ou d’utilitaires similaires. La version de Nuxt gère automatiquement l’hydratation du payload SSR. Utiliser le useFetch d’une autre bibliothèque contourne complètement cela, causant une double récupération et des désynchronisations d’hydratation.

Utiliser $fetch dans setup sans useAsyncData

Appeler $fetch directement dans <script setup> s’exécute à la fois sur le serveur et le client :

// ❌ Récupère deux fois
const data = await $fetch('/api/users')

// ✅ Récupère une fois, s'hydrate correctement
const { data } = await useFetch('/api/users')

Réservez $fetch pour les gestionnaires d’événements et les interactions client uniquement.

Réutiliser des clés avec des options conflictuelles

Cela déclenche des avertissements et des bugs :

// ❌ Options deep conflictuelles
await useAsyncData('users', fetchUsers, { deep: false })
await useAsyncData('users', fetchUsers, { deep: true })

S’attendre à des données avant l’hydratation avec server: false

Lorsque vous définissez server: false, les données restent null jusqu’à ce que l’hydratation soit terminée—même si vous await le composable.

Conclusion

Le modèle de récupération de données de Nuxt 4 repose sur l’exécution serveur, l’hydratation du payload et la mise en cache basée sur les clés. Gardez les clés stables et uniques par source de données. Assurez la cohérence des options lors du partage de clés entre composants. Utilisez useFetch ou useAsyncData pour une récupération compatible SSR, et réservez $fetch pour les interactions côté client.

Maîtrisez ces patterns, et vous éviterez les bugs de double récupération et de partage d’état qui frustrent la plupart des développeurs Nuxt.

FAQ

Cela se produit généralement lorsque vous utilisez $fetch directement dans script setup au lieu de useFetch ou useAsyncData. Les appels directs à $fetch s'exécutent à la fois sur le serveur et le client. Enveloppez vos récupérations dans useFetch ou useAsyncData pour tirer parti de l'hydratation du payload, qui récupère une fois sur le serveur et réutilise ces données côté client.

Utilisez useFetch lorsque vous récupérez directement depuis une URL—il gère les clés automatiquement en fonction de l'URL. Utilisez useAsyncData lorsque vous avez besoin de logique personnalisée, de combiner plusieurs appels API, ou d'un contrôle explicite sur la clé de cache. Les deux offrent les mêmes avantages d'hydratation SSR.

Les composants partageant la même clé partagent un état réactif identique. Pour garder les données indépendantes, utilisez des clés uniques pour chaque composant. Par exemple, utilisez users-sidebar et users-main au lieu de simplement users lorsque deux composants récupèrent le même endpoint mais ont besoin d'états séparés.

L'option dedupe contrôle comment Nuxt gère plusieurs appels de rafraîchissement. Définir dedupe sur cancel annule toute requête en attente avant d'en démarrer une nouvelle. Cela aide à éviter les conditions de concurrence lors d'interactions utilisateur rapides et garantit que les réponses plus récentes ont la priorité lorsque l'annulation est prise en charge.

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.

OpenReplay