How does it work Vue2 reactivity system?
Tags: vue, webdev, javascript, programming
Published: 2021-02-21 16:50:30

Quite often, as developers, we tend to use many frameworks and libraries as a black box, without really understanding what's going on under the hood. And that is okay, in fact is great we can effectively work with a library without worrying about how it works.

But though this concept of abstraction is important, understanding the basic concepts behind how a library/framework works is equally important. 

Here we'll see which are the basic concepts behind Vue2 reactivity system. Believe or not, there's nothing magical on it, you can achieve the same behavior with plain JavaScript.

## Object.defineProperty() method

The main responsible for reactivity is a static method in `Object` class,  `defineProperty()`. 

This method was introduced by [ES5](https://it.wikipedia.org/wiki/ECMAScript), and allows us to add a new object property, or define a new one, the difference from a simple assignment is that you can define some more details about the property.

`Object.defineProperty(obj, propertyName, descriptor)` accepts three arguments:

- `obj`, the object on which to define the property
- `propertyName`, the name of the property to be defined or modified
- `descriptor`, the descriptor for the property being defined or modified

The `obj` and `propertyName` should not require any further explanations,  instead `descriptor` does.

There are two types of descriptors: **data descriptors** and **accessor descriptor**.

Data descriptors are meant to define regular properties, so beyond the property value, you can define three additional flags: which define which actions are allowed on a specific object property.

Accessor descriptor, are more interesting for our purpose. Such descriptor is defined by a getter/setter pair of functions, and supports the following flags: configurable and enumerable. Inside get/set the value of this is set to object through which the property is accessed.

***
💡 You can dive deeper on how descriptor flags affect the property on [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).

![carbon](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fjx1o8chfpbdfm7hk7sr.png)
 
## How that can be useful for reactivity?

You may asking how this `Object.defineProperty()` might be useful for reactivity purpose, it's quite normal, with such simple example. So let me explain in words what is going on here:

- **get**, let you define a custom function to read a property, no big computation here... most of the times you'll simply return a  property's value
- **set**, let you define a custom functions to set a property... when you land here, two things are given for sure: the property's value has been changed and you can run whatever you want.

The set definition should have hint you something... 

Let's say we have a function, named **renderFunction**, which automatically  retrieve the value of every needed property in order to render our templated HTML, then, every time a setter is accessed **renderFunction** is called again, and performs the update of our document.

That is the basic logic behind reactivity explained to a 5 years old kid.

## Vue2 reactivity in concrete

Okay, let' see an overview about how Vue2 use all this to make things reactive.

![data](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/trorahhxu5yfxcph86fr.png)
 
 
Let's break the components of this diagram down.

- **VirtualDOM**, represents our document to be rendered, we don't need to understand how it works for the purpose
- **Component Render Function**, is the function responsible for update the VirtualDOM after every data changes
- **Watcher**, is a core element for the component reactivity. It records all component's dependencies (all the properties involved during rendering process)
- **Data,** is a property registered as dependency for the component, which has its own getter and setter (the ones we talked earlier)

Now let's see the flow of the above diagram.

1. **First render:** if a data is accessed, its getter calls the component's watcher which register this data as a dependency. In this way every change on the property will run the code inside its setter function.
2. The component render function **perform the render** of the document. A lot more complexity is hidden behind this statement, but it's not the purpose of the article, so a definition like that it's fine.
3. **A data is updated** somewhere (no matters where), its setter notify all the watchers which include the data as dependency.
4. **Re-render is triggered** by the watcher and performed by render function.

## Conclusion

We have seen an overview of Vue2 reactivity system, its workflow, and how it takes advantage of the `Object.defineProperty()` built-in method. Actually the same logic is behind a lot of modern libraries/frameworks, so take this article as a starting point to understand on your own how your favorite framework's reactivity works.

Some useful resources to dive deeper in this topic:

- To better understand the `Object.defineProperty()`:
    - [Property flags and descriptors](https://javascript.info/property-descriptors)
    - [Property getters and setters](https://javascript.info/property-descriptors)
    - [Object.defineProperty()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)

- Understand the reactivity in Vue2:
    - [Reactivity: Vue 2 vs Vue 3](https://www.vuemastery.com/blog/Reactivity-Vue2-vs-Vue3/)
    - [How Reactivity works in Vue.js](https://deepsource.io/blog/reactivity-in-vue/)
    - [Reactivity in Depth](https://it.vuejs.org/v2/guide/reactivity.html)