Reactivity has to be one of the most stand-out features of Vue. The feature allows this JavaScript framework to build interactive user interfaces for their front end, and the best part is, you don’t have to understand how it works, for it to work!
Reactivity is a programming pattern that allows the adjustment to the changes in a declarative manner. Here is how it offers a magic function, with a quick example.
Suppose you are working on an excel sheet that looks something like this:
A | |
1 | 5 |
2 | 3 |
3 | 8 |
Now, the A3 cell is defined by the function A1+A2. When you change the values in A1 and A2, the values in A3 will change automatically.
The caveat here is, that this does not happen in vanilla JavaScript.
If the variables in JavaScript are defined as 1 and 2, the A3 will give you an output of 3. However, if the values of A1 and A2 are changed, the A3 will not change automatically.
You will need to use the update function. The need here would be to invoke update(), whenever the dependencies (A1 and A2) are changed.
whenDepsChange(update) will do the job for you. It will track the variable reading. When evaluating A1+A2, it will read both A1 and A2. Since both of them are read when update() is executed, the update() is subscribed to both A1 and A2 after the first call.
Here, when a value is changed in A1 and A2, the re-run will occur by notifying all the subscribers to implement the change in the value.
How does this help you with Vue and reactivity? Let’s find out.
In development, it would be impossible to track the reading and writing of local variables as we did in the example above. However, if we intercept the reading and writing of object properties, that can be done.
With getter/setters and Proxies, property access can be intercepted. Vue 2 uses getter/setter as there are browser support limitations. Vue 3, on the other hand, uses getter/setters for the refs and Proxies for reactive objects.
If you are working with the data property ‘message’ in the Vue component, and you are rendering this message in the view with text interpolation like this,
Vue.component(“my-component”, { data: { message: “Hello, world” }, template: “<p>{{ message }}</p>” }); |
You will see <p>Hello, world</p> when the app instantiates. But if you modify the message in the app lifecycle like this:
methods: { updateMessage () { this.message = “Goodbye, world”; } } |
Here, Vue will update your message automatically as <p>Goodbye, world</p>. Once again, changing the dependencies will affect the outcome in the desired way, as we discussed earlier.
This is just one example of reactivity in Vue, but with the right understanding, the possibilities are endless. This can be applied for updates in DOM, calculations of a computed property, and other custom functionalities.
The reactivity in Vue 2 works by walking through each property, component prop, computed property, and everything that the user has declared on getters and setters, which will trigger the desired side effect when the dependencies are modified.
For example, let’s explore this Vue component.
const data = { id: 1, name: “X Item”, price: 999 } Vue.component(“X-item”, { data }); |
Here, the data object would be walked through. The getters and setters will be added automatically, the ones who are responsible for reactivity.
This is how the data object of the component will look at the runtime:
id: 1 name: “X Item” price: “999”
|
The ES5 Object.defineProperty() is used by Vue to convert the data object properties into getters and setters. With getters and setters added, the modification in the data will re-render the side effect:
methods: { onClick () { data.price = 1000; // triggers re-render of the component } } |
When Vue 2 was designed, there was no way to observe the changes in the property in JavaScript. If you were to add any new property to the data object during the lifecycle, the automatic reactivity would not work. Because of the limitations of Object.defineProperty(), some data changes go undetected.
In our ‘X-Item’ example above, if we were to add another dimension, a data property of ‘quantity’ (qty), the new property would not be reactive. If you modify that quantity, it will not affect the output the way you might have intended.
const data = { id: 1, // reactive name: “X Item”, // reactive price: 999 // reactive }; Vue.component(“my-item”, { data }); data.qty = 5 // will not be reactive |
The property of ‘quantity’ will be added to the data object at the runtime, however, there will be no getter/setters defined for that property, making it non-reactive.
These non-reactive properties can cause problems and in the future, prove to be difficult to diagnose. Developers working with Vue 2 stay away from adding or removing data properties because of that.
Apart from that, setting array items by index and modifying the length of an array would also result in data changes that Vue 2 will not be able to detect.
You can, however, resolve it with the Vue.set method (Vue.set(data, “qty”, 5);) to add the reactive data property after instantiation. This, however, kills the purpose of reactivity since it is not automatic and you will have to remember to use it.
Vue also came up with the Vue.observable() API method to cover all properties, but it isn’t even close to what Reactivity in Vue 3 offers. Let’s move on to that now.
The biggest difference between Vue 2 vs Vue 3 reactivity is the dependencies on the reactivity features to convert the data into getters and setters. Vue 3 has ‘Proxy’ and ‘Reflect’ to build the reactivity.
In Vue 2, if it wasn’t aware of all the dependencies of the data at the time of instantiation, you wouldn’t get the desired output. Proxy and Reflect are here to mitigate those caveats in Vue 2 reactivity.
Let’s understand the proxy first. If you want to order food from a restaurant, you can call them or order online on their website. Proxy, however, is like a food delivery app that will give you added information like live tracking of your food or seeing the reviews of the restaurants.
The proxy of Vue 3 will get you the best of both worlds. It wraps the objects you want to observe and any operations made on the objects during the runtime. Let’s understand it in terms of coding:
let data = { message: “Hello, world” }; // object we want to make reactive const proxy = new Proxy(data, { // Declaring a new Proxy object to wrap that data set (target, property, value) { // Declaring a set function target[property] = value; console.log(target); } }); proxy.message = “Goodbye, world”; /* Console: { message: “Goodbye, world” } */ |
Here, we have a data object we want to make reactive, declare a proxy to wrap the data, and the set function that will intercept set operations applied to the target data. With that, you can get desired output when the dependencies will be modified.
Now, you can add new properties during the app lifecycle and they will be automatically reactive as the proxies are observing the whole object, unlike Vue 2.
On the same lines, Reflect is an object that provides us with methods for interceptable JavaScript operations. They are the same methods you can use in your Proxy handler. The use of Reflect is to ensure the ‘this’ element does not break when an object has values or functions inherited from another object. It allows the proxy to get the ‘get’ requests where ‘this’ will be unbreakable.
The reactivity feature of Vue is a blessing for developers when they want desired side-effects of outputs out of dependencies automatically.
Vue 2 featured getters and setters for reactivity, where the addition or subtraction of any kind of data property would not be read by Vue, and the results in the output would not reflect the data modification. Compared to that, Vue 3 uses proxies, where the whole data is observed and ‘set’ is used to make the additional components reactive.
What we have discussed today is just a fraction of the utilities of what can be achieved with a feature like reactivity, what has changed in Vue 3 reactivity compared to Vue 2, and the limitations of the version.
However, under the hood for both versions, reactivity functions on the same concept. If you are working with a Vue JS development company India, transitioning from Vue 2 to Vue 3 would be smooth, and the additional APIs won’t be a hurdle.