Photo by Tadeusz Lakota on Unsplash
Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.
In this article, we'll look ar the ways to rerender a Vue.js component, and which way is the right way.
The Bad Way — Reloading the Whole Page
The whole point of having a single page app is to not have to reload the whole page to update data. Therefore, it's bad to have the whole page reload to rerender the component.
For instance, we shouldn't write anything like the following code:
Vue.component("foo", {
data() {
return {
names: ["foo", "bar", "baz"]
};
},
methods: {
reload() {
location.reload();
}
},
template: `
<div>
<button @click='reload'>Reload</button>
<p v-for='n in names'>{{n}}</p>
</div>
`
});
We have location.reload()
which we shouldn't call in a single-page app.
Another Bad Way — v-if Hack
The v-if
directive only renders the page only when the condition is true
. If it's false
, it won't be in the DOM.
The v-if
hack works by setting the v-if
condition to false
, and then setting it back to true
on the next DOM update cycle by calling $nextTick
.
For instance, we can write something like the following code to toggle the render condition to false
and then toggle it back to true
in the next update cycle:
Vue.component("foo", {
data() {
return {
names: ["foo", "bar", "baz"],
render: true
};
},
methods: {
reload() {
this.render = false;
this.$nextTick(() => {
this.render = true;
});
}
},
template: `
<div v-if='render'>
<button @click='reload'>Reload</button>
<p v-for='n in names'>{{n}}</p>
</div>
`
});
We did that by writing:
this.render = false;
this.$nextTick(() => {
this.render = true;
});
We set this.render
to false
and then set this.render
back to true
in the $nextTick
callback. This will remove the div from the DOM and then put it back on again.
This will remove the old div component and create a new div component after the $nextTick
callback is called.
$nexTick
also returns a promise so we can write:
Vue.component("foo", {
data() {
return {
names: ["foo", "bar", "baz"],
render: true
};
},
methods: {
async reload() {
this.render = false;
await this.$nextTick();
this.render = true;
}
},
template: `
<div v-if='render'>
<button @click='reload'>Reload</button>
<p v-for='n in names'>{{n}}</p>
</div>
`
});
Better Way — Call $forceUpdate
We can call $forceUpdate
to force the update of a Vue.js component. $forceUpdate
won't refresh the values of computed properties, so it won't work for refreshing computed properties.
To use it, we can write the following:
Vue.component("foo", {
data() {
return {
names: ["foo", "bar", "baz"],
};
},
methods: {
reload() {
this.$forceUpdate();
}
},
template: `
<div>
<button @click='reload'>Reload</button>
<p v-for='n in names'>{{n}}</p>
</div>
`
});
We just need to add this.$forceUpdate();
to make the component reload.
Photo by Kumiko SHIMIZU on Unsplash
The Best Way — Adding Key Props
The best way to ensure that our items refresh properly is to add a key
prop with a unique value to the items we render. It'll only recreate the component if the key
value matches what we're updating.
The key
has to be tied to a specific item on the list so that Vue will know what to update. If this is the case, it'll only rerender the item that has changed in the list since it knows which object is updated in by the unique ID that we set the key
value as.
For instance, we can add a key
prop to our v-for
items as follows:
Vue.component("foo", {
data() {
return {
names: [
{ id: 1, name: "foo" },
{ id: 2, name: "bar" },
{ id: 3, name: "baz" }
]
};
},
template: `
<div>
<p v-for='n in names' :key='n.id'>{{n.name}}</p>
</div>
`
});
We just bind to the key
prop with the value we want to and it'll update as needed.
Conclusion
The best way to ensure that v-for
items rerender properly is to use the key
prop. We just need to pass in a unique ID. $forceUpdate
can also be used to reload the page if needed.
Never should we use hacks or reload the whole page.
That's it for this topic. Thank you for reading.