React

Fetching dati in Nuxt 3: useFetch, useAsyncData e $fetch

useFetch è useAsyncData più $fetch. Usa useFetch nel setup per i dati della pagina, useAsyncData per una sorgente qualsiasi e $fetch dentro gli eventi.

In sintesi

  • useFetch chiama $fetch dal server e trasferisce il risultato al client nel payload, senza una seconda richiesta.
  • La key deve essere stabile: una chiave casuale rompe il riuso del payload e raddoppia le chiamate.
  • Dentro un handler di click useFetch non funziona: serve $fetch e un refresh esplicito.

In Nuxt 3 useFetch è useAsyncData con $fetch già collegato: esegue la chiamata sul server, mette il risultato nel payload e lo riusa durante l’idratazione, senza una seconda richiesta dal browser.

Il caso normale: dati della pagina


const { data, status, error, refresh } = await useFetch("/api/posts", {
  key: "posts",
  query: { page: 1 },
  transform: (rows) => rows.filter((row) => row.published),
});



  Loading...
  Failed: {{ error.message }}
  
    {{ post.title }}
  

await davanti a useFetch fa attendere il risultato prima del render, quindi il server risponde con l’HTML già pieno. Togli l’await e ottieni lo stesso dato in streaming, con uno stato di caricamento visibile.

Sorgenti che non sono URL


const route = useRoute();

const { data: post } = await useAsyncData(
  () => `post-${route.params.slug}`,
  () => $fetch(`/api/posts/${route.params.slug}`),
  { watch: [() => route.params.slug] },
);

La chiave è una funzione che dipende dalla rotta: cambia con lo slug e il payload resta coerente. watch rifà la chiamata quando lo slug cambia, mentre $fetch dentro la funzione è la chiamata vera e propria.

Dentro un evento serve $fetch

async function save(title: string) {
  await $fetch("/api/posts", {
    method: "POST",
    body: { title },
  });
  await refresh();
}

I composable di fetching vanno chiamati durante il setup, non dentro un gestore di click. Nell’handler usa $fetch e aggiorna con refresh restituito dal composable, oppure scrivi lo stato che gestisci tu.

Quale usare

CasoVincePerché
Dati della pagina al primo renderuseFetch$fetch e payload già collegati
Due chiamate da unireuseAsyncDataUna chiave, due fetch dentro Promise.all
Salvataggio da un bottone$fetchFuori dal setup il composable non esiste
Dato privato dell’utenteEndpoint serverIl payload viaggia nel browser, non è privato

Errori comuni

  • Chiave costruita con Math.random(): il payload non viene riusato e la richiesta parte due volte.
  • Leggere data.value dopo await useAsyncData senza controllare error: il template accede a un valore nullo.
  • Chiamare useFetch dentro onMounted: il composable è fuori dal contesto di setup.
  • Mettere un token in query con useFetch: finisce nel payload e quindi nell’HTML.

Il limite da mettere in conto

Tutto ciò che useFetch e useAsyncData recuperano finisce nel payload inviato al browser. Non è una cache privata del server: per dati riservati serve un endpoint che verifichi la sessione e restituisca solo ciò che l’utente può vedere.

Dove continuare

Nel catalogo: shadcn-vue, PrimeVue e Vue Flow; le sezioni con dati sono in /blocks. Le guide: struttura di un progetto Nuxt 3 e Composition API. Il confronto: i quattro livelli di cache in Next.js.

Domande frequenti

useFetch o useAsyncData?

useFetch è useAsyncData più $fetch già configurato. Usa useAsyncData quando la sorgente non è una chiamata HTTP o quando devi comporre più richieste.

Perché la richiesta parte due volte?

La chiave cambia fra server e client. Una key stabile, esplicita e senza valori casuali fa riusare il payload dell’idratazione.

Posso usare useFetch dentro un evento?

No. useFetch va chiamato nel setup. Dentro un handler usa $fetch e poi aggiorna con refresh o con lo stato che gestisci.

I dati sensibili restano sul server?

No: con useFetch e useAsyncData il risultato finisce nel payload inviato al browser. Le chiamate private vanno dentro un endpoint server.

Come gestisco lo stato di caricamento?

useAsyncData restituisce status, pending ed error. status è più preciso: pending è vero solo tra un caricamento e l’altro.