back to top

Vue.js: introduzione alla Composition API

In questa lezione parleremo della nuova Composition API introdotta a partire dalla versione 3 di Vue.js, ma che è possibile provare già nella versione 2 del framework attraverso il plugin @vue/composition-api.

Prima di proseguire è bene sottolineare che la Composition API è del tutto opzionale ed è possibile continuare ad usare le tecniche viste nelle lezioni precedenti per definire i componenti.

I cambiamenti introdotti a partire da Vue 3 sono per lo più interni al framework con l’obiettivo di rendere le applicazioni ancora più performanti sia in termini di velocità che di gestione delle risorse.

Con la nuova versione di Vue.js non si corre quindi il rischio di rivivere quanto accaduto con l’introduzione di Angular 2.

Cos’è la Composition API

La Composition API rappresenta un modo alternativo per definire i componenti, diverso da quello visto nelle precedenti lezioni in cui usavamo un oggetto di opzioni (Options API). Quest’ultimo rappresenta per certi aspetti il vero punto di forza di Vue.js perché consente di definire dei componenti in modo intuitivo, semplice e veloce. Presenta però delle limitazioni che diventano evidenti man mano che si realizzano delle applicazioni più complesse. Vediamo allora quali sono i limiti dell’Options API e in che modo vengono superati dalla nuova Composition API.

Perché è stata introdotta la composition API

Abbiamo visto che con l’Options API è estremamente semplice definire dei componenti, ma, al crescere delle dimensioni e della complessità di questi ultimi, risulta difficile leggere ed organizzare il codice di un componente. Nello stesso tempo diventa necessario adottare dei meccanismi per riutilizzare delle funzionalità comuni in componenti diversi.

Un altro problema è legato al modo in cui vengono definiti i componenti con l’Options API e al fatto che Vue modifica this per rendere possibile l’accesso a tutti i membri dell’oggetto delle opzioni. Per le ragioni appena esposte, in Vue 2 il supporto a TypeScript è limitato.

Analizziamo allora in maggior dettaglio le prime due limitazioni appena elencate e vediamo attraverso un semplice esempio in che modo Vue cerca di risolverle con l’introduzione della Composition API (In questa lezione presentaremo degli esempi semplici al fine di capire al meglio il funzionamento della Composition API, ma i benefici dell’uso di quest’ultima diventano evidenti al crescere delle dimensioni e della complessità dei componenti).

Organizzare un componente per funzionalità

Se volessimo creare un componente con l’Options API andremmo a definirlo attraverso un oggetto che presenta dei dati, dei metodi ed eventualmente delle computed properties, dei watchers, dei lifecycle hooks e così via.

Man mano che espandiamo un componente, finiamo per distribuire i vari pezzi di ciascuna funzionalità fra le diverse opzioni.

struttura di un componente usando l'Options API

Può dunque capitare di avere i dati, i metodi e le computed properties di ogni funzionalità sparsi in punti diversi dell’oggetto di opzioni. Organizzando il componente per opzioni, finiamo allora per mescolare e distribuire in sezioni separate i diversi pezzi delle varie funzionalità di un componente.

Al crescere delle dimensioni di un componente, diventa piuttosto difficile leggere il codice e collegare fra di loro i diversi blocchi di una stessa funzione. Risulta inoltre sempre più complicato provvedere alla manutenzione e all’aggiornamento del componente stesso.

Al contrario, la Composition API mira ad organizzare e strutturare un componente in base alle sue funzionalità che non saranno distribuite in vari oggetti separati come accade con l’Option API.

struttura di un componente usando la Composition API

L’intento è invece quello di raggruppare insieme ed isolare le diverse parti di ciascuna funzionalità in modo da avere alla fine dei frammenti di codice più leggibili e semplici da rivisitare ed aggiornare.

Come possiamo vedere dall’immagine riportata in alto, sostituiamo le diverse opzioni con un unico metodo setup() in cui andremo ad usare la nuova sintassi della Composition API.

Riutilizzare funzionalità comuni in più componenti

Per evitare di creare un metodo setup() lungo e di difficile lettura, andiamo poi ad estrarre in una nuova funzione (spesso in un diverso file) il codice relativo a ciascuna funzionalità. Successivamente possiamo procedere ad importare nei vari componenti le funzioni necessarie. E visto che si tratta di semplici funzioni, abbiamo anche la possibilità di passare di volta in volta dei diversi argomenti per personalizzare una data funzionalità come meglio preferiamo.

Come utilizzare la Composition API

Vediamo allora in dettaglio quanto espresso finora. Creiamo prima un semplice componente attraverso l’Option API e cerchiamo poi di definire un componente equivalente con la Composition API.

Usiamo ancora una volta Vue CLI per inizializzare una nuova applicazione e definiamo un componente che genera un numero casuale e il suo valore doppio attraverso una computed property.

<template>
  <div>
    <div>
      <label for="min">Valore minimo</label>
      <input type="range" 
        name="min" 
        id="min" 
        v-model.number="min" 
        min="0" max="10">
      {{ min }}
    </div>
    <div>
      <label for="max">Valore massimo</label>
      <input type="range" 
        name="max" 
        id="max" 
        v-model.number="max" 
        min="10" max="20">
      {{ max }}
    </div>
    <div>
      {{ randomNumber }} - {{ double }}
    </div>
    <button @click="getRandomNumber">Get a new Number</button>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        randomNumber: 0,
        min: 0,
        max: 0
      };
    },
    computed: {
      double()  {
        return this.randomNumber * 2;
      }
    },
    methods: {
      getRandomNumber() {
         // generiamo un numero casuale compreso fra i valori
         // delle proprietà `min` e `max`
         // anteponiamo il segno `+` per convertire la stringa restituita da
         // toFixed() in numero
         this.randomNumber = 
          +(Math.random() * (this.max - this.min) + this.min).toFixed(2);
      }
    }
  }
</script>

Nell’esempio riportato sopra abbiamo definito un componente attraverso l’Options API. Nel template inseriamo due elementi di input di tipo range per selezionare il valore minimo e massimo dell’intervallo in cui generare un numero casuale che assegniamo poi alla proprietà randomNumber. Attraverso un pulsante otteniamo ogni volta un nuovo valore casuale nell’intervallo specificato. Il valore casuale e il suo valore raddoppiato vengono quindi mostrati sullo schermo tramite interpolazione.

esempio di componente per la generazione di un numero casuale

Dopo aver spiegato in linea di massima il funzionamento del componente, vediamo come ridefinirlo attraverso la nuova Composition API.

Prima di descrivere in dettaglio il codice del componente, ricordiamo che se stiamo usando la versione 2 di Vue, dobbiamo prima installare @vue/composition-api. Per questo motivo lanciamo il comando npm install @vue/composition-api all’interno della cartella base della nostra applicazione che abbiamo creato con Vue CLI.

Fatto ciò, apriamo il file main.js e configuriamo Vue attraverso il metodo Vue.use() per indicare che vogliamo usare il plugin appena installato.

// solo per Vue 2
import Vue from 'vue';
import App from './App.vue';

// 1. importiamo VueCompositionApi
import VueCompositionApi from '@vue/composition-api';

// 2. Chiediamo a Vue di integrare 
//    le funzionalità di VueCompositionApi
Vue.use(VueCompositionApi);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App),
}).$mount('#app');

A questo punto possiamo finalmente definire il componente come mostrato nel frammento di codice sottostante.

<template>
  <div>
    <div>
      <label for="min">Valore minimo</label>
      <input 
        type="range" 
        name="min" 
        id="min" 
        v-model.number="min" 
        min="0" max="10">
      {{ min }}
    </div>
    <div>
      <label for="max">Valore massimo</label>
      <input 
        type="range" 
        name="max" 
        id="max" 
        v-model.number="max" 
        min="10" max="20">
      {{ max }}
    </div>
    <div>
      {{ randomNumber }} - {{ double }}
    </div>
    <button @click="getRandomNumber">Get a new Number</button>
  </div>
</template>

<script>
// in Vue 2 importiamo da '@vue/composition-api'
// in Vue 3 importiamo semplicemente da 'vue'
import { ref, computed } from '@vue/composition-api';

export default {
  name: 'RandomNumber',
  setup() {
    let min = ref(0);
    let max = ref(0);
    let randomNumber = ref(0);
    let double = computed(() => randomNumber.value * 2);

    function getRandomNumber() {
      randomNumber.value = 
        +(Math.random() * (max.value - min.value) + min.value).toFixed(2);
    }

    return {min, max, randomNumber, double, getRandomNumber};
  }
}
</script>

Il template resta invariato, in questo caso utilizziamo però il solo metodo setup() per definire il comportamento del componente.

Prima di tutto abbiamo importato due funzioni: ref() e computed().

Con la funzione ref(valoreIniziale) chiediamo a Vue di aggiungere una variabile al sistema di reattività e tener traccia di eventuali cambiamenti. Nell’esempio creiamo una variabile min con valore iniziale pari a 0. Ogni volta che il suo valore subisce un cambiamento, Vue reagisce opportunamente aggiornando i dati all’interno del template dell’applicazione. È importante notare che la funzione ref() restituisce un oggetto che incapsula il valore corrente all’interno di una proprietà value. Per ottenere allora il valore effettivo di un ref, dovremo accedere alla proprietà value, per esempio min.value.

La funzione computed(), la quale accetta come argomento una funzione che restituisce un valore, ha lo stesso compito dell’omonimo oggetto usato nel caso dell’Options API. Facendo riferimento all’esempio, double viene ottenuta moltiplicando il valore di randomNumber per 2. Ogni volta che randomNumber subisce una variazione, viene ricalcolato automaticamente il valore di double. Il comportamento è quindi del tutto simile a quello già visto per le computed properties il cui valore viene aggiornato ogni volta che le proprietà, da cui dipendono, vengono modificate. Notiamo che per ottenere il valore corrente di randomNumber, abbiamo dovuto accedere alla sua proprietà .value.

All’interno del metodo setup() possiamo anche avere delle funzioni come nel caso di getRandomNumber() che modifica il valore corrente di randomNumber assegnando un nuovo numero casuale compreso fra min e max.

Per stabilire quali variabili e funzioni devono essere visibili e possono essere usate all’interno del template, il metodo setup() restituisce un oggetto (abbiamo usato la sintassi abbreviata disponibile a partire da ES2015, {min} è equivalente a {min: min} in cui il valore della proprietà min fa riferimento ad un’omonima variabile). Nel template sono disponibili solo le variabili e le funzioni presenti nell’oggetto restituito da setup().

È importante notare che all’interno del template non è necessario accedere alla proprietà .value dei refs in quanto Vue si occupa di estrarre automaticamente il valore.

Ref vs Reactive

Per aggiungere dei dati al sistema di reattività, abbiamo utilizzato la funzione ref() che ha come limite la necessità di dover ogni volta accedere al valore del ref attraverso la sua proprietà .value.

È importante osservare che quando si fa uso dei refs, abbiamo solitamente una serie di tipi di dato primitivo salvati in singole variabili.

Se vogliamo invece utilizzare un oggetto per raggruppare insieme ed isolare i vari dati, Vue mette a disposizione una diversa funzione, ovvero reactive(). Riscriviamo allora l’esempio precedente usando ora la funzione reactive() e vediamo in dettaglio cosa cambia rispetto a ref().

<template>
  <div>
    <div>
      <label for="min">Valore minimo</label>
      <input 
        type="range" 
        name="min" 
        id="min" 
        v-model.number="data.min" 
        min="0" max="10">
      {{ data.min }}
    </div>
    <div>
      <label for="max">Valore massimo</label>
      <input 
        type="range" 
        name="max" 
        id="max" 
        v-model.number="data.max" 
        min="10" max="20">
      {{ data.max }}
    </div>
    <div>
      {{ data.randomNumber }} - {{ data.double }}
    </div>
    <button @click="getRandomNumber">Get a new Number</button>
  </div>
</template>

<script>
// in Vue 2 importiamo da '@vue/composition-api'
// in Vue 3 importiamo semplicemente da 'vue'
import { reactive, computed } from '@vue/composition-api';

export default {
  name: 'RandomNumber',
  setup() {
    let data = reactive({
      min: 0,
      max: 0,
      randomNumber: 0,
      double: computed(() => data.randomNumber * 2)
    });

    function getRandomNumber() {
      const {min, max} = data;
      data.randomNumber = 
        +(Math.random() * (max - min) + min).toFixed(2);
    }

    return { data, getRandomNumber };
  }
}
</script>

Partiamo da setup() e notiamo che in questo caso alla funzione reactive() passiamo un intero oggetto di proprietà. La variabile, che abbiamo deciso di nominare data, contiene tutti i dati del nostro componente. All’interno dell’oggetto abbiamo anche usato la funzione computed() per fare in modo che la proprietà data.double sia dipendente da data.randomNumber e venga automaticamente ricalcolata ogni volta che quest’ultima subisce delle modifiche.

L’aspetto negativo di reactive() è legato alla necessità di dover esportare l’intero oggetto data e non poter estrarre le singole proprietà per non perdere la funzione di reattività. Per questo motivo, nel template facciamo riferimento ai dati dell’oggetto usando la sintassi data.property, per esempio data.min.

Vue offre una soluzione a questo inconveniente, possiamo infatti importare la funzione toRefs() che converte l’oggetto passato alla funzione reactive in un oggetto di refs. Usando poi l’operatore spread (...object), possiamo rendere visibili nel template le singole variabili come mostrato nell’esempio aggiornato che riportiamo sotto.

<template>
  <div>
    <div>
      <label for="min">Valore minimo</label>
      <input 
        type="range" 
        name="min" 
        id="min" 
        v-model.number="min" 
        min="0" max="10">
      {{ min }}
    </div>
    <div>
      <label for="max">Valore massimo</label>
      <input 
        type="range" 
        name="max" 
        id="max" 
        v-model.number="max" 
        min="10" max="20">
      {{ max }}
    </div>
    <div>
      {{ randomNumber }} - {{ double }}
    </div>
    <button @click="getRandomNumber">Get a new Number</button>
  </div>
</template>

<script>
// in Vue 2 importiamo da '@vue/composition-api'
// in Vue 3 importiamo semplicemente da 'vue'
import { reactive, toRefs, computed } from '@vue/composition-api';

export default {
  name: 'RandomNumber',
  setup() {
    let data = reactive({
      min: 0,
      max: 0,
      randomNumber: 0,
      double: computed(() => data.randomNumber * 2)
    });

    function getRandomNumber() {
      const {min, max} = data;
      data.randomNumber = 
        +(Math.random() * (max - min) + min).toFixed(2);
    }
    // convertiamo in un oggetto di `refs`
    // ed estraiamo le singole proprietà
    // con l'operatore spread (...object)
    // In questo modo avremo accesso diretto nel template
    // senza dover far riferimento all'oggetto `data`
    // Invece di `data.min`, useremo semplicemente `min` ecc...
    return { ...toRefs(data), getRandomNumber };
  }
}
</script>

Non esiste quindi una netta differenza fra ref() e reactive(). Entrambe servono per aggiungere delle informazioni al sistema di reattività del framework. Come abbiamo potuto notare dagli esempi, ognuna ha dei vantaggi e degli svantaggi. Al momento il team di Vue non sembra suggerire quale sia la soluzione migliore, ma molti sviluppatori preferiscono utilizzare ref() rispetto a reactive().

Lifecycle hooks e setup()

Dopo questa breve introduzione, potremmo domandarci quando viene invocato il metodo setup() e come fare per definire i metodi del ciclo di vita del componente con la nuova Composition API.

I metodi del ciclo di vita di un componente restano quelli già visti nelle lezioni precedenti ad eccezione di beforeCreate e created al posto dei quali dovremo invece usare proprio il metodo setup() che è quindi il primo ad essere eseguito dopo che è stato completato il processo di risoluzione delle props e l’istanza del componente è stata opportunamente creata.

Infatti, a voler essere più precisi, setup() riceve in ingresso due argomenti: il primo contiene eventuali props passate al componente, il secondo è un oggetto a cui ci si riferisce solitamente con il nome context. Quest’ultimo consente di ottenere le proprietà e i metodi che in Vue 2 erano prima accessibili tramite this, per esempio attrs, slots, refs emit.

<script>
  export default {
    props: {
      propName: number
    },
    setup(props, context) {
      console.log(props.propName);
      // context.attrs
      // context.emit
      // context.parent
      // context.refs
      // context.slots
      console.log(context);
    }
  }
</script>

Per definire gli altri lifecycle hooks basterà importare una delle funzioni corrispondenti che sono nella forma on___, per esempio onMounted(), onUpdated() ecc…

// in Vue 2 importiamo da '@vue/composition-api'
// in Vue 3 importiamo semplicemente da 'vue'
import { 
  reactive, 
  toRefs, 
  computed, 
  onBeforeMount, 
  onMounted 
} from '@vue/composition-api';

export default {
  name: 'RandomNumber',
  setup() {
    let data = reactive({
      min: 0,
      max: 0,
      randomNumber: 0,
      double: computed(() => data.randomNumber * 2)
    });

    // definiamo il comportamento in ciascuna fase
    // del ciclo di vita di un componente
    onBeforeMount(() => console.log('02: metodo beforeMount()'));
    onMounted(() => console.log('03: metodo mounted()'));

    function getRandomNumber() {
      const {min, max} = data;
      data.randomNumber = 
        +(Math.random() * (max - min) + min).toFixed(2);
    }

    console.log('01: metodo setup()');

    return { ...toRefs(data), getRandomNumber };
  }
}

Ciascuna funzione del ciclo di vita di un componente riceve come argomento un’altra funzione che viene eseguita al momento opportuno da Vue.js.

watch e watchEffect

La Composition API fornisce altri due utili funzioni per eseguire delle azioni in risposta all’aggiornamento di una variabile osservata.

La prima è watch() che si comporta come il metodo this.$watch() che abbiamo già incontrato nelle precedenti lezioni.

La funzione watch() osserva una certa risorsa ed ogni volta che questa subisce una modifica, viene eseguita una funzione callback, passata come secondo argomento. La funzione callback riceve a sua volta due argomenti che sono il valore corrente e quello precedente della risorsa osservata.

Il primo argomento della funzione watch() può essere una funzione getter che restituisce la risorsa da osservare oppure direttamente un oggetto ref (oggetto restituito dalla funzione ref()).

// passando una funzione che restituisce
// la risorsa da osservare
let data = reactive({ min: 0 })
watch(
  () => data.min,
  (minVal, prevMinVal) => {
    /* eseguita ogni volta che `min` cambia */
  }
)

// passando direttamente un ref
let min = ref(0)
watch(min, (minVal, prevMinVal) => {
  /* eseguita ogni volta che `min` cambia */
})

La funzione watch permette inoltre di osservare anche più risorse contemporaneamente. In questo caso dovremo usare un array come mostrato sotto.

watch([minRef, maxRef], ([min, max], [prevMin, prevMax]) => {
  // funzione da eseguire
})

La funzione watchEffect()

La funzione watchEffect() accetta invece come unico argomento una funzione callback che, al contrario di watch(), non riceve in ingresso il valore corrente e precedente della risorsa osservata.

La callback passata a watchEffect() viene eseguita immediatamente mentre viene configurato il sistema di reattività del framework (sistema necessario per tenere traccia delle proprietà reattive come quelle restituite da ref() e reactive()) e viene poi chiamata ogni volta che le sue dipendenze cambiano. In questo caso le dipendenze sono tutte le variabili reattive utilizzate nel corpo della funzione callback.

// in Vue 2 importiamo da '@vue/composition-api'
// in Vue 3 importiamo semplicemente da 'vue'
import { 
  watchEffect, 
  reactive, 
  toRefs, 
  computed, 
  onBeforeMount, 
  onMounted } from '@vue/composition-api';

export default {
  name: 'RandomNumber',
  setup() {
    let data = reactive({
      min: 0,
      max: 0,
      randomNumber: 0,
      double: computed(() => data.randomNumber * 2)
    });

    // callback eseguita immediatamente e 
    // ogni volta che `data.min viene aggiornato`
    watchEffect(() => console.log('Watch min:', data.min));
    
    onBeforeMount(() => console.log('02: metodo beforeMount()'));
    onMounted(() => console.log('03: metodo mounted()'));

    function getRandomNumber() {
      const {min, max} = data;
      data.randomNumber = 
        +(Math.random() * (max - min) + min).toFixed(2);
    }

    console.log('01: metodo setup()');

    return { ...toRefs(data), getRandomNumber };
  }
}

La funzione callback passata a watchEffect viene eseguita inizialmente prima che il componente sia stato montato. Per questa ragione, se abbiamo necessità di accedere ad elementi del DOM all’interno della funzione callback, dovremo inserire watchEffect nel lifecicle hook onMounted.

onMounted(() => {
  watchEffect(() => {
    // ora è possibile accedere
    // al DOM e agli elementi con attributo `ref`
  })
})

Pro e contro della Composition API

In questa lezione abbiamo introdotto la nuova Composition API, abbiamo visto solo superficialmente quali sono gli strumenti messi a disposizione da Vue, ma a questo punto è chiaro che la funzione in cui andiamo a definire il comportamento di un componente è setup().

Così come abbiamo presentato i nostri esempi finora, potrebbe sorgere il dubbio che alla fine finiamo per creare un’enorme funzione setup() in cui andiamo a definire tutte le funzionalità necessarie ad un componente.

In realtà possiamo estrarre i frammenti di codice relativi a ciascuna funzionalità ed isolarli in una funzione all’interno di un modulo javascript separato.

Il primo vantaggio della Composition API è quindi la possibilità di estrarre i singoli pezzi di logica all’interno di semplici funzioni. Per convenzione (e in modo simile a quanto accade con i React hooks da cui la Composition API ha tratto ispirazione) ai nome delle funzioni, e dei moduli che le contengono, viene anteposto il prefisso ‘use’. Facendo riferimento al nostro esempio, andremo a creare una funzione all’interno del modulo useRandomNumber.js che poi importeremo nei componenti che la useranno.

// file: src/use/useRandomNumber.js
import { ref, computed } from '@vue/composition-api';

export default function (minVal = 0, maxVal = 1, precision = 2) {
  let min = ref(minVal);
  let max = ref(maxVal);
  let randomNumber = ref(0);
  let double = computed(() => randomNumber.value * 2);

  function generateNewRandomNumber() {
    randomNumber.value = 
      +(Math.random() * (max.value - min.value) + min.value)
      .toFixed(precision);

    return randomNumber.value;
  }

  return {
    min,
    max,
    randomNumber,
    double,
    generateNewRandomNumber
  };
}

Dall’esempio ci accorgiamo che la funzione restituisce variabili e funzioni che vogliamo rendere visibili all’interno dei componenti o delle altre funzioni che le utilizzano.

Trattandosi di semplici funzioni, possiamo prevedere un qualsiasi numero di parametri per assicurare un certo livello di flessibilità e consentire ai componenti di configurare al meglio una certa funzionalità.

Possiamo poi importare le funzioni all’interno di qualunque componente e riutilizzarle per scopi diversi, evitando di dover duplicare inutilmente del codice.

Per esempio, dopo aver estratto le funzionalità per generare un numero casuale in un file separato, possiamo riscrivere il componente RandomNumber come segue.

<template>
  <div>
    <div>
      <label for="min">Valore minimo</label>
      <input 
        type="range" 
        name="min" 
        id="min" 
        v-model.number="min" 
        min="0" max="10">
      {{ min }}
    </div>
    <div>
      <label for="max">Valore massimo</label>
      <input 
        type="range" 
        name="max" 
        id="max" 
        v-model.number="max" 
        min="10" max="20">
      {{ max }}
    </div>
    <div>
      {{ randomNumber }} - {{ double }}
    </div>
    <button @click="generateNewRandomNumber">Get a new Number</button>
  </div>
</template>

<script>
import useRandomNumber from '@/use/useRandomNumber';

export default {
  name: 'RandomNumber',
  setup() {
    let {
      min,
      max,
      randomNumber,
      double,
      generateNewRandomNumber
    } = useRandomNumber();

    return  {
      min,
      max,
      randomNumber,
      double,
      generateNewRandomNumber
    };
  }
}
</script>

Oppure possiamo riutilizzare la stessa funzionalità in modo totalmente diverso in un altro componente come quello riportato sotto che mostra un elenco di numeri e consente di estrarne uno cliccando un apposito pulsante.

<template>
  <div>
    <ul>
      <li v-for="n in numbers" :key="n">{{ n }}</li>
    </ul>
    <button @click="pickANumber">Seleziona un numero</button>
    <div v-if="picked">
      Numero estratto: {{ picked }}
    </div>
  </div>
</template>

<script>
import { ref } from '@vue/composition-api';

import useRandomNumber from '@/use/useRandomNumber';

export default {
  setup() {
    const numbers = [10, 23, 33, 45, 74];
    let picked = ref(undefined);
    
    // configurazione per generare
    // numeri compresi fra 0 e numbers.length - 1
    const { generateNewRandomNumber } = 
      useRandomNumber(0, numbers.length - 1, 0);

    function pickANumber() {
      const randNum = generateNewRandomNumber();
      picked.value = numbers[randNum];
    }
    
    return  {
      numbers,
      picked,
      pickANumber
    };
  }
}
</script>

Grazie alla Composition API non avremo inoltre i problemi di collisione dei nomi che rappresentano uno dei difetti dei mixin.

Due note negative della Composition API sono invece rappresentati dall’incremento della complessità rispetto all’Options API e al fatto che ora esistono due diversi modi per definire un componente.

Altro aspetto non ottimale è legato alla necessità di dover restituire nel metodo setup() un oggetto contenente le proprietà visibili nel template del componente. Ciò consente da un lato di esporre in maniera esplicita solo le variabili e le funzioni che devono essere visibili, ma dall’altro si rischia di dover scrivere lunghi elenchi di proprietà che, in alcuni casi, possono rendere il codice poco elegante, leggibile e difficile da mantenere.

Bisogna però ricordare che la Composition API è opzionale ed è sempre possibile continuare ad usare l’Options API se lo riteniamo più opportuno.

La versione finale dell’applicazione è disponibile su Bitbucket.

Riepilogo

In questa lezione abbiamo parlato della nuova composition API introdotta in Vue 3 e disponibile nella versione precedente attraverso il plugin @vue/composition-api che installiamo tramite NPM. Abbiamo visto i benefici della Composition API che rappresenta un modo nuovo e completamente opzionale per definire i componenti. Nella prossima lezione vedremo almeno superficialmente come creare delle semplici transizioni ed animazioni all’interno di un’applicazione in Vue.js.

Pubblicitร 
Articolo precedente
Articolo successivo