Uno dei vantaggi che troviamo nei framework moderni come Vue è la gestione automatica del rendering degli elementi, è infatti il framework stesso che si occupa di andare a ridisegnare gli elementi all'interno della pagina quando necessario in modo tale da ottimizzare le performance.
Esistono però dei casi particolari, come ad esempio se stiamo lavorando in un'applicazione particolarmente complessa o magari non organizzata benissimo, dove abbiamo la necessità di forzare la ri-renderizzazione di un componente.
Per fare questa operazione esistono diverse strategie ognuna con i suoi pregi e difetti.
Attenzione: Se dobbiamo utilizzare una di queste tecniche probabilmente non stiamo utilizzando il framework nel modo corretto quindi prima di procedere valutiamo con attenzione se esistono soluzioni migliori.
Questa è la soluzione più brutale tra tutte e dovrebbe essere evitata il più possibile. utilizzare questa tecnica l'equivalente di riavviare il computer ogni volta che vogliamo chiudere un'applicazione. Se abbiamo valutato attentamente il problema e abbiamo deciso in ogni caso di procedere con questa soluzione possiamo utilizzare La proprietà window.location
per ricaricare la pagina o navigare verso una nuova rotta.
// Ricarica la pagina
window.location.reload()
// Naviga verso una nuova rotta
window.location.replace("")
A differenza della soluzione precedente con questa tecnica possiamo ricaricare il componente che ci interessa senza dover ricaricare l'intera pagina. Attraverso la funzione $nextTick e la direttiva v-if, che renderizza un componente solamente quando ha un valore true
, possiamo utilizzare un piccolo trucchetto che va a modificare questo valore a false
per una frazione di secondo in modo tale da forzare la ri-renderizzazione del componente.
<template>
<b-button v-if="isRendered" />
</template>
<script>
export default {
data() {
return {
isRendered: true
}
}
methods: {
async forceRerender() {
// Disabilita il rendering del componente
this.isRendered = false
// Attende il prossimo ciclio di aggiornamento della view
await this.$nextTick()
// Abilita il rendering del componente
this.isRendered = true
}
}
}
</script>
Questa tecnica va a distruggere a ricreare il componente quindi verrà rieseguito tutto il ciclo di vita, verranno quindi richiamanti di vari hook di created, mounted, ecc.
A differenza della soluzione precedente questa tecnica ci permette di ricaricare il componente senza però andarlo a distruggere. Questa soluzione è particolarmente utile quando riscontriamo dei problemi con la reattività di vue, può capitare infatti che in casi particolari dvue non riesca a rilevare i cambiamenti di una prop o di un data (solitamente capita su oggetti e array) ed è in casi come questo che la funzione $forceUpdate
ci può tornare utile.
<template>
<ul>
<li v-for="(item, index) of items" :key="index">
#{{ item.id }} {{ item.label }}
</li>
</ul>
</template>
<script>
export default {
data() {
return {
items: [
{ id: "abc", label: "Prova 1" },
{ id: "123", label: "Prova 2" }
]
}
}
methods: {
async setLabel() {
// Imposta la proprietà label del secondo item
this.items[1].label = "Prova 3"
/*
Vue non rileva il cambiamento perchè stiamo modificando manualmente
l'oggetto all'interno dell'array.Se avessimo utilizzando la funzione
splice o se avessimo sostituito tutto l'oggetto non avremmo
riscontrato questo problema.
*/
// Forziamo la ri-renderizzazione del componente per vedere l'item modificato
this.$forceUpdate()
}
}
}
</script>
Con l'arrivo di Vue3 questo tipo di problema non dovrebbe più verificarsi perché il sistema che gestisce la reattività è stato completamente riscritto utilizzando dei Proxy che riescono a rilevare tutti i cambiamenti che si verificano su un oggetto.
Abbiamo sicuramente già utilizzato questo attributo in altri contesti, è infatti buona norma specificarlo quando utilizziamo dei cicli for
per permettere a Vue di renderizzare le liste in modo corretto, ma esistono altri casi in cui questo attributo ci torna utile. Utilizzando l'attributo :key
possiamo associare il componente a una chiave e nel momento in cui essa verrà modificata Vue provvederà a distruggere a ricreare il componente.
<template>
<b-button :key="renderKey" />
</template>
<script>
export default {
data() {
return {
renderKey: 0
}
}
methods: {
forceRerender() {
// Incrementa il valore di renderKey in modo tale da forzare la renderizzazione
this.renderKey++
}
}
}
</script>
Tra tutte le soluzioni che abbiamo visto questa è sicuramente quella più semplice e anche la più elegante.