Cause Vue components to re-render via reactive variable values. Learn how in this post.
Sometimes we need our Vue components to re-render; however, Vue might not always re-render our components as we expect or when we want it to.
In this article, we will look at how to force a Vue component to re-render using reactive variables.
Vue components will re-render if we update the values in reactive variables.
For instance, we write:
<script setup lang="ts">
import { ref } from "vue";
const count = ref(0);
</script>
<template>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
</div>
</template>
to define the count
reactive variable and set its initial value to 0 by calling ref
.
Then we add a click event listener to the button to increment count
's value. As a result, when we click the button, count
is incremented by 1.
The ref
function is used to define a reactive state in the Vue Composition API, which triggers the component to rerender when what it returns changes value.
To do the same thing with the Vue Options API, we declare a reactive value by putting it in the object returned by the data
method.
For instance, we write:
<script>
export default {
data() {
return {
count: 0,
};
},
};
</script>
<template>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
</div>
</template>
We put count
in the object returned by the data
method and set its initial value to 0. And in the button, we do the same thing as before to increment count
by 1 when we click on it.
In Vue 3, all reactive values are wrapped in a proxy object and Vue watches for changes in the proxy changes to detect changes within reactive values.
JavaScript proxies let us intercept and redefine fundamental operations for the object we create a proxy from.
To create a JavaScript proxy, we use the Proxy
constructor. For instance, we write:
const target = {
message1: "hello",
message2: "everyone",
};
const handler = {
get(target, prop, receiver) {
console.log("get", target, prop);
return target[prop];
},
set(obj, prop, value) {
console.log("set", obj, prop, value);
return Reflect.set(obj, prop, value);
},
};
const proxy = new Proxy(target, handler);
console.log(proxy.message1);
proxy.message2 = "world";
console.log(proxy.message2);
to create the target
object which we create a proxy from. Then we use the Proxy
constructor to create a proxy object for target
.
The handler
object has the get
and set
methods, which intercept the operation for getting property values and setting them, respectively.
In the get
method, we return the target[prop]
, which is the value of the prop
property in the object. prop
has the property name string, and target
is the target
object we created the proxy from.
In set
, we call Reflect.set
to set the obj
value’s prop
property to the value
value. obj
is the object we created the proxy from, and prop
is the string with the property name. value
is the value we are setting the object property to.
From the console logs, we can see get
is called when we try to get any property value from the proxy
object. And when we set the property in a proxy object, the set
method is called.
We can change what’s returned by get
and set
to change the operations of getting and setting object property values.
For instance, we write:
const target = {
message1: "hello",
message2: "everyone",
};
const handler = {
get(target, prop, receiver) {
return `foo ${target[prop]}`;
},
set(obj, prop, value) {
return Reflect.set(obj, prop, "bar");
},
};
const proxy = new Proxy(target, handler);
console.log(proxy.message1);
proxy.message2 = "world";
console.log(proxy.message2);
to return a string with foo
before the property value in the get
method. And we set whatever property value we set in the proxy to 'bar'
. As a result, we see "foo hello"
and "foo bar"
from the two console logs, respectively.
Vue 3 uses proxies for watching reactive value changes. Therefore, it can watch for deeply nested changes in property values without us doing any extra work.
For instance, we write:
<script setup lang="ts">
import { ref } from "vue";
const nestCount = ref({ nested: { count: 0 } });
const incrementDeeply = () => {
nestCount.value.nested.count++;
};
</script>
<template>
<div class="card">
<button type="button" @click="incrementDeeply">
count is {{ nestCount.nested.count }}
</button>
</div>
</template>
to define the incrementDeeply
function. In it, we just increment the nested.count
property value directly.
This works because Vue uses JavaScript proxies to watch for deeply nested changes. So it can pick up the change to nested.count
immediately with the proxy and re-render component by watching the proxy set
method’s changes.
With the Options API, we write:
<template>
<button type="button" @click="incrementDeeply">
count is {{ nestCount.nested.count }}
</button>
</template>
<script>
export default {
data() {
return {
nestCount: {
nested: { count: 0 },
},
};
},
methods: {
incrementDeeply() {
this.nestCount.nested.count++;
},
},
};
</script>
In the data
method, we define the nestCount
reactive property. Inside it, we add the nested.count
property and set it to 0 initially.
Then we define the incrementDeeply
method and this.nestCount.nested.count
increases by 1 when we call it. And we add a click event listener to the button and call incrementDeeply
when we click it.
Because of Vue 3’s use of proxies to watch for changes, we can just set the deeply nested property’s value and it will re-render the component as a result.
Therefore, to make sure a Vue component re-renders when we want to, we should update the values of reactive variables.
We can get Vue components to re-render when we want to by updating the values of reactive variables.
Vue 3 should be able to watch for values in reactive values that are deeply nested objects because of its use of JavaScript proxies to watch for reactive value changes.
John Au-Yeung is a frontend developer with 6+ years of experience. He is an avid blogger (visit his site at https://thewebdev.info/) and the author of Vue.js 3 By Example.