Vue 3: Composition API o Options API, a cosa serve davvero ciascuna

  • vuetelemetry
  • Guide
  • 6 min di lettura

La Composition API non sostituisce la Options API. Risolvono problemi diversi a scale diverse, e la scelta dipende meno da quale sia più recente e più da come cresce il componente. Cosa fa ciascuna, dove ciascuna mostra i suoi limiti e come scegliere senza riscrivere codice che funziona.

Vue 3 include entrambe le API. La Options API è quella che Vue ha sempre avuto: un componente è un oggetto con `data`, `computed`, `methods`, `watch` e gli hook del ciclo di vita come proprietà con nome. La Composition API, introdotta con Vue 3, permette di scrivere la stessa logica come normali funzioni dentro una funzione `setup()` o un blocco `<script setup>`. Nessuna delle due è deprecata e nessuna sta per sparire.

La Options API organizza il codice per tipo di opzione. Tutto lo stato reattivo va in `data()`. Tutti i valori calcolati vanno in `computed`. Tutti i metodi vanno in `methods`. Nei componenti piccoli è chiaro, perché ogni aspetto occupa poche righe per sezione e le sezioni si scorrono in fretta. Diventa un problema quando il componente cresce: una singola funzionalità (per esempio un filtro di ricerca) ha lo stato in `data`, i valori derivati in `computed`, i gestori di eventi in `methods` e l'inizializzazione in `mounted`. La funzionalità è sparsa in quattro punti del file.

Come la Options API organizza il codice

Piste di rame su un circuito stampato nero che partono in tutte le direzioni da una piazzola ottagonale centrale, circondata da piccoli componenti a montaggio superficiale etichettati da S4 a S12.
Piste di rame su un circuito stampato nero che partono in tutte le direzioni da una piazzola ottagonale centrale, circondata da piccoli componenti a montaggio superficiale etichettati da S4 a S12.

La Composition API organizza il codice per responsabilità logica. Invece di mettere tutto lo stato in un posto e tutti i metodi in un altro, si raggruppano lo stato, i valori calcolati, i watcher e le funzioni che appartengono a una stessa funzionalità. Un filtro di ricerca diventa un blocco di 15 righe che contiene tutto ciò che gli serve. La paginazione diventa un altro blocco. Stanno uno accanto all'altro nel file, e se ne può leggere uno senza saltare in altre tre sezioni.

Conta solo nei componenti grandi. Un componente con uno stato, un valore calcolato e un metodo è leggibile allo stesso modo con entrambe le API. La Composition API comincia a ripagare quando un componente ha tre o più responsabilità indipendenti, perché è allora che la Options API costringe a intrecciare logica non correlata tra le sezioni.

Come la Composition API organizza il codice

`<script setup>` è la sintassi usata dalla maggior parte del nuovo codice Vue 3. È una scorciatoia di compilazione che evita di scrivere una funzione `setup()` esplicita con la relativa istruzione return. Le variabili dichiarate al livello superiore sono disponibili automaticamente nel template. Le props si dichiarano con `defineProps()` e gli eventi con `defineEmits()`. Sono entrambe macro del compilatore che non serve importare.

  • La Options API organizza il codice per tipo (data, computed, methods), la Composition API per funzionalità
  • Nessuna delle due API è deprecata, ed entrambe usano lo stesso sistema di reattività
  • ref() è la scelta predefinita consigliata rispetto a reactive(), per evitare bug di riassegnazione e destrutturazione
  • I composable sostituiscono i mixin per riutilizzare la logica tra componenti senza collisioni di nomi
  • L'inferenza di TypeScript funziona in modo naturale con la Composition API e fatica con il this della Options API
  • La migrazione è facoltativa: le due API convivono nello stesso progetto e persino nello stesso componente

La reattività nella Composition API si basa su `ref()` e `reactive()`. `ref()` avvolge un singolo valore e richiede `.value` per leggerlo o scriverlo in JavaScript (ma non nel template, dove Vue lo estrae automaticamente). `reactive()` avvolge un oggetto le cui proprietà sono reattive senza `.value`. La fonte di bug più comune è dimenticare `.value` nello script, oppure usarlo nel template, dove non serve.

ref, reactive e script setup

`ref()` è quasi sempre la scelta predefinita giusta. `reactive()` ha due limiti in cui molti inciampano. Primo, non si può riassegnare l'intero oggetto (il proxy è sul riferimento originale, non sulla variabile). Secondo, destrutturare un oggetto reattivo fa perdere la reattività alle proprietà estratte. `ref()` non ha nessuno dei due problemi, e il prezzo di `.value` è modesto rispetto al costo di debug di questi casi limite.

I composable sono il principale vantaggio strutturale. Un composable è una funzione che usa le primitive della Composition API (`ref`, `computed`, `watch`, `onMounted`) e restituisce stato reattivo. `useMouse()`, `useFetch()` e `useLocalStorage()` sono esempi tipici. Si chiamano in `setup()` e restituiscono valori reattivi. È lo schema che la Options API non riesce a replicare in modo pulito: i mixin condividono logica tra componenti, ma uniscono le proprietà per nome, creando collisioni silenziose e rendendo impossibile capire da dove venga una proprietà.

I mixin sono l'equivalente della Options API, e su larga scala creano problemi. Se due mixin definiscono una proprietà `data` con lo stesso nome, una delle due prevale senza avvisare. Se un mixin aggiunge un metodo, il componente non ne ha alcuna dichiarazione visibile. L'origine di una proprietà diventa ambigua man mano che si aggiungono mixin. La documentazione di Vue raccomanda esplicitamente i composable al posto dei mixin per riutilizzare la logica in Vue 3.

Composable contro mixin

Il supporto a TypeScript è nettamente migliore nella Composition API. La Options API richiede il wrapper `defineComponent()`, e l'inferenza dei tipi passa per un tipo `this` complesso che fatica con certi schemi (callback annidate, funzioni esterne che leggono lo stato del componente). La Composition API usa normali variabili con tipi TypeScript standard. `ref<number>(0)` restituisce un `Ref<number>`. I composable hanno valori di ritorno tipizzati. Il supporto dell'IDE (completamento automatico, tipi al passaggio del mouse, refactoring) funziona come con qualsiasi funzione TypeScript.

Le prestazioni a runtime sono simili, con due vantaggi documentati per la Composition API. Il sistema di reattività è lo stesso in entrambi i casi. La documentazione di Vue osserva che il codice in `<script setup>` si minifica meglio, perché il template viene compilato in una funzione nello stesso scope e i nomi delle variabili locali possono essere accorciati, mentre il codice della Options API passa per accessi a proprietà di `this`. Un progetto che usa solo la Composition API può inoltre disattivare la Options API con il flag di compilazione `__VUE_OPTIONS_API__`, che la rimuove dal bundle di produzione. Per la maggior parte delle applicazioni questi guadagni sono piccoli rispetto all'organizzazione del codice.

**Le prestazioni a runtime sono simili, con due vantaggi documentati per la Composition API.** Il sistema di reattività è lo stesso in entrambi i casi. La documentazione di Vue osserva che il codice in `<script setup>` si minifica meglio, perché il template viene compilato in una funzione nello stesso scope e i nomi delle variabili locali possono essere accorciati, mentre il codice della Options API passa per accessi a proprietà di `this`. Un progetto che usa solo la Composition API può inoltre disattivare la Options API con il flag di compilazione `__VUE_OPTIONS_API__`, che la rimuove dal bundle di produzione. Per la maggior parte delle applicazioni questi guadagni sono piccoli rispetto all'organizzazione del codice.

- vuetelemetry

TypeScript, prestazioni e migrazione

La migrazione non è obbligatoria. Vue 3 supporta entrambe le API nello stesso progetto, e nello stesso file se serve. Un componente Options API può usare un composable chiamandolo in un metodo `setup()` aggiunto accanto alle opzioni esistenti. Non serve riscrivere componenti Options API che funzionano. La via pratica è scrivere i nuovi componenti con `<script setup>` e rifattorizzare i vecchi solo quando li si sta già modificando per altri motivi.

Quando scegliere la Options API. Componenti piccoli o medi con logica semplice. Team in cui la maggior parte degli sviluppatori sta imparando Vue e trae beneficio da una struttura esplicita. Codebase già scritte con la Options API che non hanno bisogno di refactoring. Prototipazione rapida, quando dare un nome a ref e composable rallenta più di quanto aiuti l'organizzazione.

Quando scegliere la Composition API. Componenti con più responsabilità indipendenti. Qualsiasi situazione in cui serva condividere logica con stato tra componenti (i composable sostituiscono i mixin). Progetti in TypeScript. Librerie e pacchetti open source (i composable sono il formato di distribuzione atteso). Applicazioni grandi i cui file di componente superano spesso le 200 righe.

FAQ

La Options API è deprecata in Vue 3?

No. Il team di Vue mantiene entrambe le API allo stesso livello. La Options API non è deprecata, non ne è prevista la rimozione e riceve gli stessi aggiornamenti. La documentazione le presenta una accanto all'altra. Scegliere la Composition API è una decisione sull'organizzazione del codice, non sul restare aggiornati.

Devo riscrivere i miei componenti Options API con la Composition API?

Non senza un motivo che vada oltre l'API stessa. Il codice Options API che funziona non peggiora perché esiste la Composition API. L'approccio pratico è scrivere i nuovi componenti con la Composition API e rifattorizzare i vecchi solo quando li si sta già modificando e il refactoring rende la modifica più semplice.

Qual è la differenza tra ref e reactive in Vue 3?

ref() avvolge un singolo valore e richiede .value per accedervi nello script. reactive() avvolge un oggetto le cui proprietà sono reattive senza .value. La differenza pratica principale è che reactive() perde la reattività quando lo si destruttura o si riassegna l'intero oggetto, mentre ref() non ha nessuno dei due problemi. La documentazione di Vue e la maggior parte delle guide della comunità consigliano ref() come scelta predefinita.

Stack correlato