Understanding Vue.js reactivity

Published on April 18, 2017 by

Alright, so now that we know how Vue.js proxies data and methods for us, let’s talk a bit about how it reacts to changes.

We are going to use the example from the previous post, because we’ll be spending most of our time within the browser’s console again.

<div id="app">
	<h1>{{ message }}</h1>
</div>
var vm = new Vue({
	el: '#app',
	data: {
		message: 'Hello World!',
		x: 1,
		y: 2
	},
	methods: {
		showMessage: function() {
			alert(this.message);
		}
	},
	computed: {
		z: function() {
			return this.x + this.y;
		}
	}
});

console.log(vm);

Let’s open up the $data property on the Vue instance.

Here we see the reactive getters and setters that Vue automatically add for us. We briefly touched this in the last lecture, but let’s go a bit deeper now. What happens when you pass in a data object when you instantiate a Vue instance, is that Vue walks through all of the properties and converts them to these getters and setters. This is completely transparent to you as you use Vue, so unless you dive into the inner workings of Vue as we are doing now, you are not going to notice this.

So what’s the point of these getters and setters? Well, simply put, they are the reason that the DOM is updated whenever a data property changes. With these reactive functions, Vue can detect when changes are made, as well as when properties are accessed. On top of that, they allow Vue to track dependencies between data properties.

To go into just a little bit more detail, I have prepared a diagram to illustrate what I just said.

First, we have our data which contains a getter and setter function for each data property. When a setter is invoked, it sets a new value for the data property and also notifies a watcher, which is attached to the Vue instance. This watcher is responsible for reacting to data changes. When something changes, it triggers a re-render of the template by calling a render function, which is basically a function that is responsible for re-rendering a Vue instance or component. This is not important to us right now, so we won’t get into details here, but the important thing is that something re-renders the template. When rendering or processing the template, something called the virtual DOM is updated. This is also not important to understand right now, because we are going to take a closer look at it in one of the next posts. But it’s basically the step right before the DOM is updated. As I said, we’ll dive into that in one of the next posts, so don’t worry about what happens thereafter for now. When rendering, the data properties are “touched” you could say, meaning that the getter functions are invoked. This enables Vue to resolve the dependencies and notify the watcher. With this, Vue knows which properties to watch for changes, and when a value changes, the watcher reacts appropriately.

The short version of this story is that Vue uses the getters and setters for resolving dependencies and most importantly for reactiving to data changes. That’s all you really need to know. The rest is good to know, as it helps you understand what happens behind the scenes, but it’s not really a requirement to know this when working with Vue.

Now back to the code, because I want to show you something important. Did you notice that throughout this course, I have always declared data properties with an empty value if we had no value to assign to it initially? You might have wondered if that was really necessary. As you will see now, it is indeed necessary.

Let’s try to remove the message data property and add it dynamically instead, by simply using the vm variable.

vm.message = 'Hello World!';

If we take a look at the console, we will see a warning that we are using a data property that is not defined on the Vue instance. It also states that we have to declare it within the data object.

Before doing so, let’s see something interesting by adding a button that invokes the showMessage method when it is clicked.

<button @click="showMessage">Click Me!</button>

When I click the button, we see the correct message being output within the alert dialog. So why did this even work? The answer is in the console.

If we inspect the Vue instance again and look for the message property, we see that it was indeed added to the Vue instance.

However, you might also have noticed that the property has no getters or setters associated with it, meaning that no proxy functions have been added to this property. Likewise, if we take a look at the $data property, we will see that there is no sign of the message property, meaning that it has not been made reactive.

The reason for this is that Vue cannot detect when properties are added or deleted. And since Vue converts data properties into getters and setters when initializing the Vue instance, a property must be present in the data object during initialization. Otherwise Vue cannot add the proxy or reactive functions. So while the property is indeed available on the Vue instance, as we just saw when clicking the button, the property will not be reactive. So if we change it, the watcher associated with the Vue instance is not going to be notified of this, and we also cannot use it within the template.

So as you can see, there was indeed a good reason why we initialized data properties with an empty value. You simply must do this to be able to use the reactiveness of Vue.js.

While it is not possible to dynamically add new reactive top-level data properties to a Vue instance, it is possible to add a new reactive property to a nested object. This can be done by using the global Vue.set method as we have previously seen.

Now that we understand more about how Vue reacts to data changes, let’s take a look at how data is updated.

Featured

Learn Vue.js today!

Take an online course and become an Vue.js champion!

Here is what you will learn:

  • How to build advanced Vue.js applications (including SPA)
  • How Vue.js works under the hood
  • Communicating with services through HTTP
  • Managing state of large applications with Vuex
  • ... and much more!
Vue.js logo
Author avatar
Bo Andersen

About the Author

I am a back-end web developer with a passion for open source technologies. I have been a PHP developer for many years, and also have experience with Java and Spring Framework. I currently work full time as a lead developer. Apart from that, I also spend time on making online courses, so be sure to check those out!

Leave a Reply

Your e-mail address will not be published.