back to top

Vue.js: le proprietà methods, computed e watchers

Continuiamo ad esplorare le funzionalità messe a disposizione da Vue e soffermiamoci in particolare sulle cosiddette computed properties cercando di capire in cosa differiscono rispetto ai metodi. Passiamo poi a parlare di un altro tipo di opzione, ovvero di quelli che Vue chiama watchers.

Cosa sono le ‘computed properties’ in Vue.js

Nelle precedenti lezioni abbiamo visto come utilizzare la tecnica dell’interpolazione per mostrare il valore di semplici espressioni all’interno di un’applicazione e trarre vantaggio del sistema di reattività di Vue.js che provvede ad aggiornare automaticamente le informazioni al verificarsi di una modifica.

Allo stesso modo abbiamo visto che grazie alla direttiva v-bind possiamo assegnare agli attributi di un elemento HTML (o come vedremo in seguito alle ‘props‘ di un componente) dei valori dinamici.

Per evitare di usare in entrambi i casi espressioni troppo lunghe e difficili da leggere e perdere i vantaggi dell’approccio dichiarativo che contraddistingue i template, possiamo affidarci alle cosiddette computed properties.

Per definire una o più proprietà di questo tipo, dovremo aggiungere una nuova voce all’oggetto delle opzioni passato in fase di costruzione di un’istanza di Vue.

const vm = new Vue({
  el: '#root',
  data: {
    // ...
  },
  computed: {
    // per definire le 'computed properties'
  }
})

Basterà infatti aggiungere una nuova proprietà computed in cui andiamo a definire le computed properties associate all’istanza base sotto forma di funzioni.

const vm = new Vue({
  el: '#root',
  data: {
    item: {
      name: 'Matita',
      price: 0.85,
      quantity: 2,
      vat: 0.22
    }
  },
  computed: {
    formattedTotalPrice() {
      // come per i metodi, `this` si riferisce all'istanza `vm`
      // Valgono quindi le considerazioni già fatte per i metodi
      // sull'impossibilità di usare le arrow functions.
      const { price, quantity, vat } = this.item;

      const formatter = new Intl.NumberFormat("it-IT", {
        style: "currency",
        currency: "EUR",
        minimumFractionDigits: 2
      });

      const total = (1 + vat) * price * quantity;

      return formatter.format(total);
    },
    vat() {
      return `${this.item.vat * 100}%`;
    }
  }
});

Potremo poi accedere al loro valore nel template HTML attraverso un riferimento al nome della computed property, così come abbiamo fatto per le altre proprietà dell’oggetto data.

<main id="root">
  <div>Oggetto: {{ item.name }}</div>
  <div>Prezzo: {{ item.price }}</div>
  <div>Quantità: {{ item.quantity }}</div>
  <hr>
  <div>
    Prezzo Totale ({{ vat }} IVA compresa) 
    <strong>{{ formattedTotalPrice }}</strong>
  </div>
</main>
esempio con le computed properties in Vue.js

Come le proprietà dell’oggetto data, mostriamo il loro valore tramite interpolazione facendo riferimento al nome della computed property. Al contrario delle proprietà dell’oggetto data, le computed properties vengono però definite attraverso una funzione che non riceve alcun argomento e restituisce sempre un valore.

Possiamo quindi utilizzare le computed properties per generare dei nuovi valori che in qualche modo sono delle trasformazioni delle proprietà base dell’oggetto data o derivano da quest’ultime.

Nel momento in cui avvengono delle variazioni delle proprietà da cui una computed property dipende, Vue aggiorna il suo valore e provvede ad effettuare le modifiche necessarie nell’applicazione.

Facendo riferimento all’esempio visto sopra, se la proprietà quantity subisce un incremento, passando da 2 a 3 unità, Vue ricalcola il valore di formattedTotalPrice e aggiorna il nodo del DOM che mostra le informazioni in merito al prezzo totale.

Differenza fra ‘Computed Properties’ e ‘Methods’

Le computed properties assomigliano ai methods in quanto si tratta in entrambi i casi di funzioni, ma quali sono le differenze principali fra i due?

La principale differenza consiste del fatto che le computed properties vengono memorizzate in una cache interna e vengono ricalcolate solo quando almeno una delle proprietà reattive (le proprietà aggiunte in fase di definizione nell’oggetto ‘data’), da cui dipendono, subisce una variazione. Ciò significa che se dipendono solo da proprietà non reattive, le computed properties non vengono mai ricalcolate.

Vediamo allora un esempio che evidenzia il comportamento appena descritto.

Supponiamo di avere un array di prodotti. Ciascun elemento dell’array è un oggetto che contiene come informazioni il nome del prodotto, un identificativo univoco ed un prezzo. Vogliamo mostrare la somma dei prezzi dei prodotti che calcoliamo sia con un metodo total() che con una computed property totalPrice. Per evidenziare la differenza di comportamento fra i due approcci, inseriamo un contatore con un pulsante che incrementa il suo valore in modo da simulare l’aggiornamento di una diversa sezione dell’applicazione non collegata al calcolo del prezzo finale.

// app.js
const vm = new Vue({
  el: '#root',
  data: {
    counter: 0,
    items: [
      {
        id: 1,
        name: 'penna',
        price: 1.65
      },
      {
        id: 2,
        name: 'gomma',
        price: 0.99
      },
      {
        id: 3,
        name: 'matita',
        price: 0.95
      }
    ]
  },
  computed: {
    totalPrice() {
      
      console.info('> Computed Property: totalPrice');

      const total = this.items.reduce(
        (total, currentItem) => total + currentItem.price,
        0
      );
      
      return total;
    }
  },
  methods: {
    total() {

      console.info('> Method: total()');

      const total = this.items.reduce(
        (total, currentItem) => total + currentItem.price,
        0
      );

      return total;
    }
  }
});

Seguendo le indicazioni di Vue.js abbiamo definito l’oggetto delle opzioni dell’istanza base in cui sono presenti un metodo total() e una computed property totalPrice che calcolano il prezzo totale degli oggetti presenti nell’array items.

Andiamo quindi a mostrare le informazioni creando un file index.html come quello riportato sotto.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Vue.js: esempio v-for</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <main id="root">
      <ul>
        <li v-for="item in items">
          {{ item.name }} - {{ item.price }}
        </li>
        <hr>
        <div>totale restituito da computed property: <strong>{{ totalPrice }} €</strong></div>
        <div>totale restituito dal metodo total(): <strong>{{ total() }} €</strong></div>
      </ul>
      {{ counter }}
      <button @click="counter = counter + 1">incrementa contatore</button>
    </main>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="app.js"></script>
  </body>
</html>
https://vimeo.com/462643371

Come possiamo notare dal video riportato sopra, il metodo total() viene sempre invocato anche quando vengono aggiornate altre informazioni della pagina, come avviene per il contatore. Al contrario totalPrice viene ricalcolato solo quando le proprietà da cui dipende subiscono delle modifiche. In particolare quando aggiungiamo un elemento all’array items, solo in quel caso viene ricalcolato totalPrice.

L’esempio mostrato probabilmente non riesce ad evidenziare fino in fondo il beneficio che si ottiene dall’uso delle computed properties rispetto ai metodi. Se però dovessimo ricalcolare ogni volta un valore effettuando operazioni dispendiose in termini computazionali, capiamo bene che riutilizzare un valore senza doverlo ricalcolare inutilmente, può portare notevoli vantaggi.

Computed setters

Normalmente le computed properties stabiliscono il comportamento delle proprietà solo quando viene richiesto il loro valore. Possiamo però indicare quali operazioni devono essere eseguite anche quando viene passato un nuovo valore ad una computed property attraverso set (setter). Tramite i costrutti sintattici get e set indichiamo rispettivamente quale funzione deve essere eseguita se accediamo al valore di un proprietà o se modifichiamo il suo valore.

computed: {
  fullName: {
    get: function() {
      return this.firstName + ' ' + this.lastName;
    },
    set: function(value) {
      let names = value.split(' ');
      this.firstName = names[0];
      this.lastName = names[names.length - 1];
    }
  }
}

Se ora passiamo a fullName un nuovo valore, questo verrà suddiviso e verranno automaticamente impostati firstName e lastName.

Cosa si intende per ‘watchers’ in Vue.js

Le computed properties rappresentano la scelta migliore in svariate situazioni, ma ci sono casi in cui è necessario avere maggiore controllo sulle modifiche apportate ad una proprietà, in particolar modo per eseguire operazioni dispendiose o asincrone in seguito alla sua variazione.

I watchers sono lo strumento di Vue.js che consente di tener sotto controllo una proprietà dell’oggetto data dell’istanza ed eseguire una funzione quando il valore di quella proprietà cambia.

Basterà in questo caso aggiungere una nuova proprietà all’oggetto delle opzioni con cui costruiamo un’istanza di Vue, ovvero la proprietà watch nella quale definiamo delle funzioni con lo stesso nome della proprietà che vogliamo osservare. Tale funzione può avere anche due parametri, il primo rappresenta il nuovo valore assegnato alla proprietà, il secondo è invece il valore precedente.

const vm = new Vue({
  el: '#root',
  data: {
    counter: 0,
    items: [
      {
        id: 1,
        name: 'penna',
        price: 1.65
      },
      {
        id: 2,
        name: 'gomma',
        price: 0.99
      },
      {
        id: 3,
        name: 'matita',
        price: 0.95
      }
    ]
  },
  computed: {
    totalPrice() {
      
      console.info('> Computed Property: totalPrice');

      const total =
        this.items.reduce(
          (total, currentItem) => total + currentItem.price,
          0
        );
      
      return total;
    }
  },
  methods: {
    total() {

      console.info('> Method: total()');

      const total =
        this.items.reduce(
          (total, currentItem) => total + currentItem.price,
          0
        );

      return total;
    }
  },
  watch: {
    counter(newValue, oldValue) {
      console.log('Aggiornamento counter:');
      console.log('Vecchio valore: ', oldValue);
      console.log('Nuovo valore: ', newValue);
    },
    items() {
      console.log('Modifica array items!');
    }
  }
});

A questo punto verranno mostrate le relative informazioni nella console per sviluppatori ogni volta che counter e items subiscono delle variazioni che Vue è in grado di rilevare.

Riepilogo

In questa lezione abbiamo concentrato la nostra attenzione su quelle che Vue.js chiama Computed properties e abbiamo visto in cosa differiscono dai metodi. Le computed properties vengono definite attraverso delle funzioni, ma vengono utilizzate nei template HTML come delle normali proprietà facendo riferimento al loro nome all’interno delle doppie parentesi graffe o come espressione di direttive come v-bind Abbiamo infine introdotto un’altra proprietà dell’oggetto delle opzioni che usiamo in fase di costruzione di un’istanza di Vue, ovvero la proprietà watch che permette di definire una funzione che verrà eseguita ogni volta che una proprietà omonima subisce una variazione.

Pubblicitร