Vue.js 3.0.0 alpha was released on January 2020, and nine months later, on September 2020, vue-next
3.0 was released officially with the code name "One Piece" (yes, the anime). There was a lot of changes with the Vue 3, but I will discuss mainly on the new reactivity system for which I've been waiting.
In order to facilitate your understanding, this article contains simple codes that highlight the flow of the reactivity systems of vue@2.6.12
and vue-next@3.0.4
.
Preface
Before we dive into how reactivity system in Vue 3 works, let’s take a look at how it is implemented in Vue 2 and some of its caveats. Vue 2 implements reactivity system by going through all attributes of the data
option that is passed to the Vue instance and using the Object.defineProperty
.
Here’s how the code works, step-by-step.
- Vue walks through each and every property of
data
object with thewalk()
and addsget/set
traps. - The
getter
that was passed as parameter is executed with thenew Watcher()
. Then, Vue accessesdata.a
anddata.b
and activates theget
trap.
2.1.dep.depend
is called, and whendata.a
changes,dep.depend()
executesDep.target
that usesdata.a
and makes it reactive.
2.2. The steps for thedata.b
'sget
trap is the same as 2.1. sum
is evaluated to be3
.data.a
is changed to7
.data.a
'sset
trap is called and calls thedep.notify()
.- The
subs
array found indep
has agetter
, so thegetter
is executed to reevaluate the value ofsum
to be 9.
Vue 2 reactivity system uses the Object.defineProperty
, and therefore, cannot detect if a new property is added to the object or if an element of an array changes. Vue 2 had to use vm.$set()
method to induce notify()
by force. For arrays, if you take a look at observer/array.js
, internal methods like push
, pop
, and shift
support reactivity.
Vue 3 Reactivity
In Vue 3, you can make a reactive proxy like const obj = reactive({a: 0})
. The Vue 3 reactivity system itself functions similarly to the Vue 2 reactivity system.
track
the code when you access a valuetrigger
the tracked code when the value changes.
Let’s take it step by step.
track
: the code that will be executed reactively
Vue 3 uses the Map
, Set
, and WeakMap
to implement the reactive data system. (obj
and effect
were used strictly as examples.)
If you map out the collection structure above, you get the following.
targetMap<WeakMap>
tracks thetarget
that will be a reactive object.depsMap<Map>
becomes the values for each reactive object and stores thekey
for eachtarget
.dep<Set>
collection tracks the codes that are executed every time thekey
is changed.
trigger
: executes the tracked code
Now, here’s the basics of the trigger
. The trigger
finds the depsMap
from the targetMap
and then finds and executes the code to execute from the dep
through the trap's key
.
reactive
: creating the reactive object
Let’s look at the reactive
function that calls track
and trigger
. Unlike Vue 2, Vue 3 uses a Proxy
to implement the reactivity. Proxy
does not modify the original object unlike Object.defineProperty
and can detect new properties or changes of an object.
activeEffect
So far, there is a small problem with the code. Whenever we access all properties of a reactive object, the get
trap is called, calling track
and continuously adding effect
to deps
. Furthermore, some reactive objects may require automatic response expressions to be registered manually.
Vue addresses this issue by the activeEffect
variable. The code that will be executed reactively, the response expression, is only added to the deps
when the activeEffect
exists in the get
trap.
Putting it all together
Let’s put everything together and look at the flow of the Vue 3 Reactivity as a whole.
Here’s how the code works, step-by-step.
- Create a reactive proxy with
reactive({a: 1, b: 2})
. - Pass and execute the
sumFn
to theeffect
function.
2.1.sumFn
is assigned to theactiveEffect
.
2.2.sumFn
is executed.
2.2.1. Accessnumbers
a
andb
, and sinceactiveEffect
exists, set thesumFn
to be executed later indeps<Set>
.
2.2.2.3
is assigned to thesum
as the function executes. - Pass and execute the
multiplyFn
to theeffect
function, and the steps 2.1 and 2.2 are repeated. - When the
numbers.a
changes, Vue finds all functions tracked ina
'sdeps<Set>
and executes every function.
Conclusion
The official Vue 3 Reactivity guide goes over a lot more of reactive handling, so taking the time to read through the document should help your understanding and development. In 2020, Vue released a web development kit Vite along with the Vue 3, and Ionic, framework used for hybrid web development, developed @ionic/vue, which is compatible with Vue 3.
In 2021, I look forward to more tools and companion libraries to gain compatibility with Vue.js 3, thereby extending the realm of Vue.js.