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.
The main responsible for reactivity is a static method in
This method was introduced by ES5, 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
propertyName should not require any further explanations, instead
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.
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.
Okay, let' see an overview about how Vue2 use all this to make things reactive.
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.
- 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.
- 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.
- A data is updated somewhere (no matters where), its setter notify all the watchers which include the data as dependency.
- Re-render is triggered by the watcher and performed by render function.
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: