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
| Caso | Vince | Perché |
|---|---|---|
| Dati della pagina al primo render | useFetch | $fetch e payload già collegati |
| Due chiamate da unire | useAsyncData | Una chiave, due fetch dentro Promise.all |
| Salvataggio da un bottone | $fetch | Fuori dal setup il composable non esiste |
| Dato privato dell’utente | Endpoint server | Il 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.valuedopoawait useAsyncDatasenza controllareerror: il template accede a un valore nullo. - Chiamare
useFetchdentroonMounted: 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.