back to top

Componenti dinamici in Vue.js

Cosa si intende per componenti dinamici

Finora abbiamo visto come mostrare o nascondere dei componenti attraverso le direttive v-if e v-else. In questa lezione illustreremo come rimpiazzare dei componenti e quindi visualizzarne solo uno alla volta sullo schermo attraverso la tecnica dei componenti dinamici. Si tratta di un metodo per sostituire dinamicamente dei componenti inseriti nello stesso nodo DOM senza far uso di Vue Router e senza dover quindi cambiare il percorso corrente dell’URL.

L’elemento <component></component>

Seguendo la solita filosofia e con l’obiettivo di semplificare al massimo la procedura sopra descritta, Vue ha introdotto l’elemento <component> che andremo ad utilizzare insieme all’attributo is.

All’interno del template di un componente possiamo allora aggiungere l’elemento <component> come mostrato nel frammento di codice riportato sotto.

<div class="container">
  <component :is="visibleComponent"></component>
</div>

Sull’elemento <component> applichiamo l’attributo is e grazie alla direttiva v-bind (nell’esempio abbiamo usato la sintassi abbreviata per v-bind, ovvero ‘:’) lo associamo alla proprietà visibleComponent la quale conterrà una stringa relativa al nome di uno dei componenti che vogliamo montare nel DOM. Basterà poi cambiare il valore di visibleComponent per rimuovere il componente corrente ed inserirne uno nuovo.

Espandiamo allora l’esempio riportato sopra e creiamo all’interno di una nuova cartella 4 componenti nei rispettivi file: Component1, Component2, Component3 e App.

App sarà il nostro componente principale in cui sostituiremo in maniera dinamica gli altri tre componenti che riportiamo di seguito.

// Component1
<template>
  <div>
    <input type="text" placeholder="Inserisci il tuo nome...">
  </div>
</template>


<style scoped>
input[type="text"] {
  border: 1px solid hsl(213, 87%, 9%);
  border-radius: 4px;
  padding: 8px 12px;
}
</style>
// Component2
<template>
  <div>
    <p>Component 2</p>
  </div>
</template>
// Component3
<template>
  <div>
    <p>Component 3</p>
  </div>
</template>

Nel componente App importiamo poi i tre componenti appena creati ed utilizziamo l’elemento <component> per sostituire di volta in volta il componente visibile nella pagina.

// App.vue
<template>
  <div class="container">
    <div 
      class="selector-wrapper" 
      v-for="selector in selectors" 
      :key="selector.id"
    >
      <input 
        type="radio" 
        :id="selector.id" 
        :value="selector.value" 
        v-model="visibleComponent">
      <label :for="selector.id">{{ selector.label }}</label>
    </div>
    <div class="component-wrapper">
      <component :is="visibleComponent"></component>
    </div>
  </div>
</template>

<script>
import Component1 from './Component1';
import Component2 from './Component2';
import Component3 from './Component3';

export default {
  name: 'App',
  components: {
    Component1,
    Component2,
    Component3
  },
  data() {
    return {
      selectors:[
        {id: 'component-1', label: 'Component 1', value: 'Component1'},
        {id: 'component-2', label: 'Component 2', value: 'Component2'},
        {id: 'component-3', label: 'Component 3', value: 'Component3'}
      ],
      visibleComponent: 'Component1'
    }
  }
}
</script>

<style scoped>
.selector-wrapper {
  display: inline-block;
  margin-right: 24px;
}

.component-wrapper {
  margin-top: 24px
}
</style>

Nel file App.vue creiamo tre elementi di input di tipo radio attraverso la direttiva v-for. Su ciascuno di questi applichiamo la direttiva v-model che li associa alla stessa proprietà visibleComponent. In questo modo, ogni volta che viene selezionato un diverso elemento di tipo radio, viene prelevato il valore dell’attributo value che viene poi assegnato alla stessa proprietà visibleComponent. Questa può quindi assumere valore ‘Component1’, ‘Component2’ o ‘Component3’. Non appena visibleComponent cambia, viene passato un nuovo valore all’attributo is applicato sull’elemento <component> e di conseguenza nel DOM vengono inseriti gli elementi presenti nel template del componente corrente.

Per semplicità possiamo visualizzare l’esempio appena creato usando la funzione di Instant Prototyping di Vue CLI.

https://vimeo.com/462643914

A questo punto abbiamo visto come sostituire i componenti in maniera dinamica, ma, se osserviamo per un momento il pannello Network degli strumenti per sviluppatori del browser, notiamo che vengono inizialmente scaricate tutte le risorse necessarie, compreso il codice dei componenti Component2 e Component3 inizialmente non visibili.

Nel caso del nostro esempio sarebbe utile se potessimo rimuovere dal bundle iniziale il codice relativo ai componenti Component2 e Component3.

In nostro soccorso Vue offre la possibilità di suddividere il file javascript di un’applicazione in più parti e scaricare inizialmente solo la porzione di codice necessaria.

Vue CLI semplifica tale procedura e con l’aiuto di Webpack basterà usare la funzione import() in fase di registrazione dei componenti.

Modifichiamo allora il file App.vue per usufruire della funzione di code splitting.

// App.vue
<template>
  <div class="container">
    <div 
      class="selector-wrapper" 
      v-for="selector in selectors" 
      :key="selector.id"
    >
      <input 
        type="radio" 
        :id="selector.id" 
        :value="selector.value" 
        v-model="visibleComponent">
      <label :for="selector.id">{{ selector.label }}</label>
    </div>
    <div class="component-wrapper">
      <component :is="visibleComponent"></component>
    </div>
  </div>
</template>

<script>
import Component1 from './Component1';
// import Component2 from './Component2';
// import Component3 from './Component3';

export default {
  name: 'App',
  components: {
    Component1,
    Component2: () => import('./Component2'),
    Component3: () => import('./Component3')
  },
  data() {
    return {
      selectors:[
        {id: 'component-1', label: 'Component 1', value: 'Component1'},
        {id: 'component-2', label: 'Component 2', value: 'Component2'},
        {id: 'component-3', label: 'Component 3', value: 'Component3'}
      ],
      visibleComponent: 'Component1'
    }
  }
}
</script>

<style scoped>
.selector-wrapper {
  display: inline-block;
  margin-right: 24px;
}

.component-wrapper {
  margin-top: 24px
}
</style>

Se ora visualizziamo nuovamente l’applicazione nel browser, notiamo che in questo caso vengono scaricati due nuovi file con estensione .js solo nel momento in cui i componenti Component2 e Component3 vengono inseriti nel DOM per la prima volta.

https://vimeo.com/462643768

La funzione di code splitting può essere utile ed efficace man mano che aumentano le dimensioni dell’applicazione. Nel caso di pochi semplici componenti, come quelli dell’esempio appena visto, i benefici non sono evidenti e a volte si rischia addirittura di aumentare le dimensioni del bundle iniziale dovendo includere funzioni e frammenti di codice altrimenti non presenti.

Mantenere lo stato dei componenti dinamici con <keep-alive>

Prima di concludere questa lezione, evidenziamo un ultimo problema dei componenti dinamici e vediamo poi una possibile soluzione.

Se analizziamo l’esempio illustrato finora, notiamo che i componenti inseriti nel DOM tramite l’elemento <component> vengono distrutti e ricreati ogni volta che si passa da uno all’altro. Questo tipo di comportamento può causare delle conseguenze inaspettate nel caso di componenti che mantengono uno stato interno. Se, per esempio, inseriamo del testo all’interno del campo di input di Component1 e poi attiviamo un altro componente, ci accorgiamo che il testo digitato viene perso visto che Component1 viene distrutto e poi rimontato.

https://vimeo.com/462643812

Per risolvere questo tipo di inconvenienti è possibile racchiudere l’elemento <component> all’interno dell’elemento <keep-alive> come mostrato sotto.

<div class="component-wrapper">
  <keep-alive>
  <component :is="visibleComponent"></component>
  </keep-alive>
</div>

https://vimeo.com/462643808

Nel breve video della demo notiamo che vengono stampati dei messaggi nella console visto che abbiamo definito i due Lifecycle hooks activated() e deactivated(). Questi si aggiungono a quelli visti nella lezione precedente e valgono solo per i componenti dinamici racchiusi in <keep-alive>. Il primo metodo viene invocato quando il componente viene attivato ed è quindi visibile, il secondo al contrario è eseguito quando il componente viene disattivato per cedere posto ad un altro componente.

<template>
  <div>
    <p>Component 3</p>
  </div>
</template>

<script>
export default {
  name: 'Component3',
  activated() {
    console.log('Component3 activated');
  },
  deactivated() {
    console.log('Component3 deactivated'); 
  }
}
</script>

Riepilogo

In questa breve lezione abbiamo parlato di quelli che in Vue vengono definiti componenti dinamici. Abbiamo visto che si tratta di una tecnica per mostrare o nascondere facilmente dei componenti in base ad una certa condizione. Abbiamo infine illustrato uno esempio in cui abbiamo utilizzato <keep-alive> per mantenere lo stato di un componente che viene sostituito. Nella prossima lezione approfondiremo il tema dei form in Vue.js e rincontreremo la direttiva v-model che abbiamo già incontrato nell’esempio in cui abbiamo realizzato una semplice applicazione per tenere traccia degli impegni.

Pubblicitร 
Articolo precedente
Articolo successivo