React
watch e computed in Vue 3: quando usare quale
computed produce un valore e non ha effetti collaterali, watch esegue codice quando una sorgente cambia: la scelta dipende dall’output, un dato o un effetto.
In sintesi
- Se la funzione restituisce un valore, è un computed; se esegue un effetto, è un watch.
- computed mette in cache il risultato e ricalcola solo quando cambia una dipendenza.
- watch dichiara le sorgenti, riceve vecchio e nuovo valore e accetta cleanup per annullare richieste.
Usa computed quando devi ottenere un valore da altro stato e watch quando devi eseguire un effetto: una richiesta, un log, un salvataggio. Se la funzione non restituisce un valore, non è un computed.
Computed: un valore derivato
import { computed, ref } from "vue";
const query = ref("");
const rows = ref([]);
const visible = computed(() =>
rows.value.filter((row) =>
row.name.toLowerCase().includes(query.value.toLowerCase()),
),
);
Il filtro gira una volta per cambiamento di query o rows, non a ogni render. computed tiene il risultato in cache finché una dipendenza non cambia: è questa la differenza pratica con un metodo chiamato nel template.
Watch: un effetto con una sorgente
import { ref, watch } from "vue";
const id = ref("1");
const user = ref(null);
watch(
id,
async (value, _old, onCleanup) => {
const controller = new AbortController();
onCleanup(() => controller.abort());
const res = await fetch("/api/users/" + value, {
signal: controller.signal,
});
user.value = await res.json();
},
{ immediate: true },
);
Qui il risultato non è un valore da mostrare ma una richiesta da lanciare. immediate esegue subito, onCleanup annulla la chiamata precedente quando id cambia o il componente smonta.
La scelta in tre righe
| Caso | Vince | Perché |
|---|---|---|
| Totale del carrello | computed | Valore derivato, nessun effetto |
| Salvataggio automatico della bozza | watch | Scrive fuori dallo stato, serve un effetto |
| Titolo della pagina dal nome utente | watch | Tocca document.title, non un valore |
| Filtro di una lista | computed | Cachato e leggibile nel template |
Errori comuni
- Assegnare dentro un
computed: il compilatore avvisa e la cache diventa imprevedibile. - Usare
watchEffectper un valore derivato: raccoglie dipendenze in modo implicito e ricalcola senza controllo. - Osservare un oggetto grande con
deep: true: il costo di traversal supera il beneficio. - Dimenticare il cleanup: due richieste in volo scrivono lo stato nell’ordine sbagliato.
Il limite da mettere in conto
Nessuna delle due funzioni risolve il problema del primo caricamento: un computed asincrono restituisce una Promise, non il dato. Per un valore che arriva dalla rete servono un ref e un watch con cleanup, come nell’esempio sopra.
Dove continuare
Nel catalogo: shadcn-vue, PrimeVue e Vuetify; le tabelle con filtro sono in components. Le guide: Composition API e Pinia. Il confronto: stato derivato in React e Vue vs React.
Domande frequenti
Posso usare computed dentro watch?
Sì, e spesso conviene: watch su un computed reagisce al valore derivato invece che a ogni campo che lo compone.
watch o watchEffect?
watch dichiara le sorgenti e riceve vecchio e nuovo valore, watchEffect raccoglie le dipendenze da solo ed è comodo per effetti brevi.
computed può essere asincrono?
No. Una funzione async dentro computed restituisce una Promise e il valore non viene atteso: per un dato asincrono serve watch più un ref.
Perché il mio watch non parte?
La sorgente non è reattiva. Una funzione getter su una variabile normale non notifica nulla: passa un ref o una funzione che legge un ref.
Meglio watch con deep?
Solo sugli oggetti che cambi in profondità. Su strutture grandi il costo di traversal supera il beneficio e conviene osservare un campo preciso.