Reactivity System in Vue.js

Ehsan Movaffagh
3 min readJun 23, 2023

Introduction

Hello there! In this story, we will delve into the Reactivity System in Vue3 applications. To begin, let’s explore the concept of the observer pattern.

Observer Pattern

The Observer Pattern is a design pattern that involves an object known as the subject. The subject maintains a list of its dependents, referred to as observers/subscribers, and automatically notifies them of any state changes by invoking their respective methods.

Take a look at an implementation of simple observer pattern:

class Subject {
__value

constructor(value) {
this.__value = value
this.__observers = []
}

set value(newValue) {
this.__value = newValue
for (const observer of this.__observers) {
observer.update(this)
}
}

get value() {
return this.__value
}

subscribe(observer) {
this.__observers.push(observer)
}
}

class Observer {
update(subject) {
console.log(`new value: ${subject.value}`)
}
}

In our code, you can see that after each set for our subject, the update method will be executed for all of its observers. Now, let’s create a subject and an observer to test this code.

Now, as you can see, our observer is notified, and it logs the subject’s new value in the console.

Reactivity System

Introduction

A ref or reactive property (subject) stores a dep (dependency) object, which is essentially a set of effects (observers in above code). When we retrieve a value from a ref, the track method is called. On the other hand, when we assign a value to a ref, the trigger method is invoked, indicating that a change has occurred in the reactive property. We will soon discuss effects, tracks and triggers.

Effect

In simple terms, an effect in Vue can be seen as an observer.

class Effect {

constructor(fn) {
this.fn = fn
}

// for a computed it will update inner value and
// for a component it will render needed part of that
run() {
return this.fn()
}
...
}

The effect object, when instantiated, receives a function in its constructor. The main responsibility of the effect is to observe any changes in reactive properties within that function.

At any given moment, there exists only one active effect known as ActiveEffect. In the following section, we will explore how ActiveEffect allows us to observe any changes in reactive properties and their effects.

Track and Trigger method

When a reactive property value is accessed within a new code scope, such as a render function or computed getter method, the track function is triggered. ActiveEffect is added to the dependents of the reactive property. In this scenario, the ActiveEffect is an initialized effect used in a computed or component to detect changes in reactive properties. This mechanism ensures that the computed or component is aware of any modifications to the reactive property.

function track(target) {
// component.effect or computed.effect is equal to activeEffect
// it is actually a subscriber
target.dep.add(activeEffect)
}

When the value of a reactive property is changed, the trigger function is called. However, the trigger function only runs the effects associated with it if the new value is different from the old value. In this way, the trigger ensures that only effects dependent on the changed value are executed.

function trigger(target) {
const effects = [...target.dep]
for (const effect of effects) {
// we will run effect of our reactive property. one of this effects
// are computed.effect. and now computed can update its inner value
effect.run()
}
}

Conclusion

And here we are! Now you have an understanding of how the reactivity system works in Vue.js. In this story, the code snippets may not be clear. In the upcoming stories, we will make sure to fix them and improve their clarity.

hope you enjoy!

--

--

Ehsan Movaffagh

Full-stack developer & software engineer, crafting innovative solutions to shape the digital world🚀; https://linkedin.com/in/ehsan-movaffagh