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.
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.
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.
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>
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.