Vue - Reactivity System in Depth (1)

Vue’s reactivity system is powerful. If we change a data value somehow in the code, it automatically updates the page to reflect that change. While I enjoy the reactivity system most of the time, it can cause a lot of frustration and stress when it doesn’t work as expected. So instead of desperately searching answers on Google why my data doesn’t get updated, I decided to learn the reactivity thoroughly.

The reactivity system is implemented based on Object.defineProperty. When a Vue instance is initialized, it will iterate through all the properties defined in data, and use Object.defineProperties to turn all properties into getters and setters, as so to use them to respond to data changes. Limited by modern JavaScript (as well as obsolete of Object.observe), Vue cannot detect addition or deletion of an object property. Since Vue performs getter/setter conversion on object properties when it is initialized, the property must exist on the data object beforehands.

Example code from the official guide

1
2
3
4
5
6
7
8
9
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` is now reactive

vm.b = 2
// `vm.b` is NOT reactive

In the above code, vm.b is not injected during instance initialization, thus it is not reactive.

Watcher

Vue implements a watcher-subscriber pattern to accomplish data-driven views. The getter/setter methods of an object are used to listen for data changes, and each setter is exactly a watcher for observing updates. Each component has a corresponding watcher instance object, which records the property as a dependency during component rendering. When the dependency setter is called, it notifies the watcher to reevaluate the data, causing its associated component to update.

1
2
3
4
5
6
7
8
9
10
11
12
var vm = new Vue({
data () {
return {
name: 'hello'
}
},
computed: {
cname: function () {
return this.name + ' world'
}
}
}

There are two key elements in the above code, a data property name and a computed property cname, where name and cname is a watcher-subscriber relationship. When cname() is executed, name will be called via its getter. At this point, the watcher (created for each computed property as well) corresponding to cname will be notified as a subscriber, thus reevaluating the value.

References