Profile picture of Marc Backes (very handsome) Profile picture of Marc Backes (very handsome)
Marc Backes

Create Your Own State Reactivity

April 25, 2020 ยท by Marc Backes
Profile picture of Marc Backes (very handsome) Profile picture of Marc Backes (very handsome)
Create Your Own State Reactivity Create Your Own State Reactivity
he most important part of a framework like Vue is its reactivity. In this post, we build our own Vue.js-like reactivity step by step.

This post is the fourth part of a series called Create Your Own Vue.js From Scratch, where I teach you how to create the fundamentals of a reactive framework such as Vue.js. To follow this blog post, I suggest you first read the other parts of the series.

What is state reactivity?

State reactivity is when we do something (react) when the state of our application (set of variables) changes. We do this in two steps:

  1. Create a "reactive dependency" (We get notified when a variable changes)
  2. Create a "reactive state" (Basically a collection of dependency variables)

1. Building a reactive dependency

Function to watch over changes

For this to work, we first need a function that is executed when a reactive dependency changes. As in Vue, this is called watchEffect; we'll also call our function that.

In our example, this function looks like this:

function watchEffect(fn) {
  activeEffect = fn
  activeEffect = null

The global variable activeEffect is a temporary variable where we store our function, passed to watchEffect. This is necessary, so we can access the function when itself reads a dependency that refers to that function.

Dependency class

We can see a reactive dependency as a variable that notifies to its subscribers when it's value changes.

  • It can be created with an initial value, so we need a constructor
  • We need to subscribe a function to changes on the dependency. We'll call this depend()
  • We need a to notify subscribed functions of the dependency when the value changes. We'll call this notify()
  • We need to do something when the value gets read or written, so we need a getter and a setter

So our skeleton will look like this:

class Dep {
  // Initialize the value of the reactive dependency
  constructor(value) {}

  // Subscribe a new function as observer to the dependency
  depend() {}

  // Notify subscribers of a value change
  notify() {}

  // Getter of the dependency. Executed when a part of the software reads the value of it.
  get value() {}

  // Setter of the dependency. Executed when the value changes
  set value(newValue) {}

The class has two fields: value (value of the dependency) and subscribers (set of subscribed functions).

We implement this step by step.


In the constructor, we initialize the two fields.

constructor(value) {
    this._value = value // not `value` because we add getter/setter named value
    this.subscribers = new Set()

subscribers needs to be a Set, so we don't repeatedly subscribe to the same function.

Subscribe a function

Here, we need to subscribe a new function as an observer to the dependency. We call this depend.

depend() {
    if (activeEffect) this.subscribers.add(activeEffect)

activeEffect is a temporary variable that is set in the watchEffect which is explained later on in this tutorial.

Notify subscribers of a dependency change

When a value changes, we call this function, so we can notify all subscribers when the dependency value changes.

notify() {
    this.subscribers.forEach((subscriber) => subscriber())

What we do here is to execute every subscriber. Remember: This is a subscriber is a function.


In the getter of the dependency, we need to add the activeEffect (a function that will be executed when a change in the dependency occurs) to the list of subscribers. In other words, use the depend() method we defined earlier.

As a result, we return the current value.

get value() {
    return this._value


In the setter of the dependency, we need to execute all functions that are watching this dependency (subscribers). In other words, use the notify() method we defined earlier.

set value(newValue) {
    this._value = newValue

Try it out

The implementation of dependency is done. Now it's time we try it out. To achieve that, we need to do 3 things:

  • Define a dependency
  • Add a function to be executed on dependency changes
  • Change the value of the dependency
// Create a reactive dependency with the value of 1
const count = new Dep(1)

// Add a "watcher". This logs every change of the dependency to the console.
watchEffect(() => {
  console.log('๐Ÿ‘ป value changed', count.value)

// Change value
setTimeout(() => {
}, 1000)
setTimeout(() => {
}, 2000)
setTimeout(() => {
}, 3000)

In the console log you should be able to see something like this:

๐Ÿ‘ป value changed 1
๐Ÿ‘ป value changed 2
๐Ÿ‘ป value changed 3
๐Ÿ‘ป value changed 4

You can find the complete code for the dependency on ๐Ÿ‘‰ Github.

2. Building a reactive state

This is only the first part of the puzzle and mainly necessary to understand better what is going to happen next.

To recap: We have a reactive dependency and a watch function that together give us the possibility to execute a function whenever the variable (dependency) changes. Which is already pretty damn cool. But we want to go a step further and create a state.

Instead of somthing like this:

const count = Dep(1)
const name = Dep('Marc')
id.value = 2
name.value = 'Johnny'

We want to do something like this:

const state = reactive({
  count: 1,
  name: 'Marc',
state.count = 2 = 'Johnny'

To achieve this, we need to make some changes to our code:

  • Add the reactive function. This created the "state" object.
  • Move getter and setter to the state instead of the dependency (because this is where the changes happen)

So the dependency (Dep) will only serve as such. Just the dependency part, not containing any value. The values are stored in the state.

The reactive function

The reactive() function can be seen as an initialization for the state. We pass an object to it with initial values, which is then converted to dependencies.

For each object property, the following must be done:

  • Define a dependency (Dep)
  • Definer getter
  • Define setter
function reactive(obj) {
  Object.keys(obj).forEach((key) => {
    const dep = new Dep()
    let value = obj[key]
    Object.defineProperty(obj, key, {
      get() {
        return value
      set(newValue) {
        if (newValue !== value) {
          value = newValue
  return obj

Changes on the dependency

Also, we need to remove the getter and setter from the dependency, since we do it now in the reactive state:

class Dep {
  subscribers = new Set()
  depend() {
    if (activeEffect) this.subscribers.add(activeEffect)
  notify() {
    this.subscribers.forEach((sub) => sub())

The watchEffect function stays the same.

Try out the code

And we are already done with converting our dependency variable into a reactive state. Now we can try out the code:

const state = reactive({
  count: 1,
  name: 'Marc',

watchEffect(() => {
  console.log('๐Ÿ‘ป state changed', state.count,

setTimeout(() => {
  state.count++ = 'Johnny'
}, 1000)

setTimeout(() => {
}, 2000)
setTimeout(() => {
}, 3000)

In the console log you should see something like this:

๐Ÿ‘ป state changed 1 Marc
๐Ÿ‘ป state changed 2 Marc
๐Ÿ‘ป state changed 2 Johnny
๐Ÿ‘ป state changed 3 Johnny
๐Ÿ‘ป state changed 4 Johnny

You can find the complete code for the reactive state on ๐Ÿ‘‰ Github.

Summary โœจ

That's it for this part of the series. We did the following:

  • Create a dependency with a value inside, which notifies a subscribed function when the value changes
  • Create a state where a subscribed function is called for the change of every value