Controllo di flusso

4 luglio 2017

Nei primi articoli della guida abbiamo introdotto molto superficialmente le direttive v-if e v-for. È giunto il momento di scendere nei dettagli e di approfondire il loro comportamento.

Rendering condizionale

Il rendering condizionale è abbastanza triviale: grazie ad alcune direttive è possibile definire quali elementi del DOM della pagina mostrare in base ad alcune condizioni particolari. Questo viene ottenuto tramite le direttive v-if, v-else-if e v-else. Ecco un esempio chiarificatore:

<div id="vue-app">
  <input type="text" v-model="age">
  <template v-if="age > 18">
     Puoi guidare la macchina
  </template>
  <template v-else-if="age > 14">
    Puoi guidare il motorino
  </template>
  <template v-else>
    Ti tocca andare in bici
  </template>
</div>

Un’alternativa alla direttiva v-if è v-show che a differenza del primo non appende nuovi elementi al dom, ma semplicemente li nasconde tramite direttive CSS (la property display in particolare).

La differenza tra i due risiede nelle performance. v-if è più lento a runtime in quanto deve modificare ogni volta il DOM della pagina ma, essendo lazy, è più veloce in fase di rendering iniziale dato che renderizza solo i nodi richiesti. v-show invece è leggermente più lento nel rendering iniziale ma è nettamente più veloce a runtime. Il suggerimento è quello di utilizzare v-if per grandi frammenti poco spesso triggerati (per esempio le pagine in una single-page application) e v-show per piccoli frammenti spesso visualizzati/nascosti (per esempio un accordion o delle faqs).

Cicli

La direttiva che il framework ci mette a disposizione per le iterazioni è v-for. Essa permette di ciclare una lista di elementi e di mostrare il contenuto HTML per ciascuno di essi, come un classico for in Javascript. v-for è in grado di ciclare sia array numerici che associativi, permettendo accedere sia al valore che all’indice. Ecco due esempi:

var vm = new Vue({
  el: '#vue-app',
  data: {
    people: [
      'Alberto',
      'Marco',
      'Luca',
      'Andrea'      
    ],
    drinks: {
      'water': 3,
      'code': 4,
      'beer': 0
    }
  }
});
<div id="vue-app">
  <template v-for="person in people">
    {{ person }}
  </template>
  <template v-for="(quantity, drink) in drinks">
    {{ drink }} => {{ quantity }}
  </template>
</div>

Vue permette di iterare facilmente anche un intervallo di numeri con la sintassi v-for="n in 20".

Se sullo stesso nodo HTML sono presenti sia la direttiva v-for che quella v-if, la prima avrà la priorità, in modo da poter aggiungere un controllo per ogni elemento della lista. Riprendendo l’esempio di prima, possiamo aggiungere un controllo per non stampare quantità minori di 1:

<div id="vue-app">
  <template v-for="person in people">
    {{ person }}
  </template>
  <template v-for="(quantity, drink) in drinks" v-if="quantity > 0">
    {{ drink }} => {{ quantity }}
  </template>
</div>

La direttiva key

Il rendering condizionale e i cicli sono due aspetti molto utilizzati all’interno di qualsiasi applicazione Vue.js. Per questa ragione è necessario approfondire un argomento spesso spinoso per chi utilizza Vue per la prima volta e che spesso può portare a emicranie.

Per poterlo fare è però necessaria una premessa: Vue è un framework, come abbiamo ripetuto più volte, che fa delle performance la sua caratteristica vincente. Per rendere concreto questo obiettivo, gli sviluppatori di Vue hanno investito parecchio tempo nella gestione e ottimizzazion degli accessi al DOM (in quanto operazioni particolarmente onerose in termini di risorse per i browser).

Vue utilizza un sistema a patch, in quanto è in grado di applicare le modifiche al DOM nella maniera più chirurgica possibile, proprio come delle piccole patch che vengono applicate sul singolo elemento da modificare. Prendiamo questo esempio:

<div id="vue-app">
  <template v-if="condizione">
    <div class="first">
      Io sono il primo div
    </div>
  </template>
  <template v-else>
    <div class="second">
      Io sono il secondo div
    </div>
  </template>
</div>

Passando da uno stato all’altro della property condizione, Vue non smonta e rimonta i <div> incriminati, come potrebbe sembrare (e come ho detto prima), ma semplicemente modifica classe e contenuto del div già presente in pagina, alleggerendo così il lavoro del browser.

Questo pattern è molto performante ma non è totalmente gratuito per lo sviluppatore. Egli infatti deve essere a conoscienza di eventuali side effect che questo può portare. La direttiva key, che ora introdurremo, serve proprio ad evitare problemi. Prendiamo quindi un esempio fallace:

<div id="vue-app">
  <div v-for="person in people">
    <input type="text">
    {{ person }}
  </div>
  <button @click="shuffle">mischia</button>
</div>
var vm = new Vue({
  el: '#vue-app',
  data: {
    people: [
      'Alberto',
      'Marco',
      'Luca',
      'Andrea'      
    ]
  },
  methods: {
    shuffle: function() {
      this.people = this.people.sort(function() {
        return .5 - Math.random();
      });
    }
  }
});

In questo esempio abbiamo una lista di nomi e per ognuno di essi mostriamo un campo di testo. È presente inoltre un pulsante che mischia i nomi delle persone. Fintanto che i campi associati alle persone non vengono modificati, tutto funziona perfettamente: al click sul pulsante la lista viene mischiata e la reattività di Vue aggiorna automaticamente le label a fianco degli input.

Nel momento in cui l’utente andrà a scrivere qualcosa nel campo di testo associato, per esempio, ad Alberto e premerà il tasto, vedremo però (sempre che lo shuffle abbia spostato Alberto) che il campo modificato rimarrà nella prima posizione, mentre l’etichetta Alberto è stata correttamente spostata in basso. Questo è l’effetto (fallace) del motore di patching di Vue: per essere il più performante possibile, il framework ha applicato solamente le modifiche alla label, senza di fatto spostare i nodi.

Per risolvere questo comportamento è necessario introdurre la direttiva key sul <div>. La direttiva deve contenere una chiave univoca per ciascun elemento del ciclo e permette a Vue di associare univocamente non solo la label, ma tutta la struttura DOM al indice corrente del ciclo, trasferendo di fatto tutto lo stato in caso di ulteriore shuffle. Ecco quindi la versione corretta:

<div id="vue-app">
  <div v-for="person in people" :key"person">
    <input type="text">
    {{ person }}
  </div>
  <button @click="shuffle">mischia</button>
</div>

Se questo comportamento può sembrare un limite non banale, è importate sottolineare che la priorità viene data alle performance e che i casi in cui la direttiva key è fondamentale non sono molti, di fatto tutti quelli in cui sono presenti stati non incapsulati nelle property interessate da v-if o da v-for (come appunto il valore del campo input nell’esempio precedente).

Tutte le lezioni

1 ... 5 6 7

Se vuoi aggiornamenti su Controllo di flusso inserisci la tua e-mail nel box qui sotto:
 
X
Se vuoi aggiornamenti su Controllo di flusso

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy