Create Your Own Vue.js From Scratch - Part 4 (Building The Reactivity)
Tags: vue, javascript
Published: 2020-04-25 10:41:03

If you like this article, chances are you'd like what I tweet as well. If you are curious, have a look at my [Twitter profile](https://twitter.com/_marcba). 🚀

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 read about the other parts of this series first.

# Roadmap 🚘

1. [Introduction](https://dev.to/_marcba/coding-a-vue-js-like-framework-from-scratch-part-1-introduction-3nbf)
2. [Virtual DOM basics](https://dev.to/_marcba/create-your-own-vue-js-from-scratch-part-2-virtual-dom-basics-58fm)
3. [Implementing the virtual DOM & rendering](https://marc.dev/blog/vue-from-scratch-part-3)
4. Building reactivity (this post)
5. [Bringing it all together](https://dev.to/_marcba/create-your-own-vue-js-from-scratch-part-5-bringing-it-all-together-4eb3)

# 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:

```javascript
function watchEffect(fn) {
    activeEffect = fn
    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:

```javascript
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.

### Constructor

In the constructor, we initialize the two fields.

```javascript
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`.

```javascript
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.

```javascript
notify() {
    this.subscribers.forEach((subscriber) => subscriber())
}
```

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

### Getter

In the _getter_ of the dependency, we need to add the `activeEffect` (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.

```javascript
get value() {
    this.depend()
    return this._value
}
```

### Setter

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.

```javascript
set value(newValue) {
    this._value = newValue
    this.notify()
}
```

## 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

```javascript
// 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(() => {
    count.value++
}, 1000)
setTimeout(() => {
    count.value++
}, 2000)
setTimeout(() => {
    count.value++
}, 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](https://gist.github.com/themarcba/f4d15000999f8921c584b6f78bff2867).

# 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:

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

We want to do something like this:

```javascript
const state = reactive({
    count: 1,
    name: 'Marc',
})
state.count = 2
state.name = '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_

```javascript
function reactive(obj) {
    Object.keys(obj).forEach((key) => {
        const dep = new Dep()
        let value = obj[key]
        Object.defineProperty(obj, key, {
            get() {
                dep.depend()
                return value
            },
            set(newValue) {
                if (newValue !== value) {
                    value = newValue
                    dep.notify()
                }
            },
        })
    })
    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:

```javascript
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:

```javascript
const state = reactive({
    count: 1,
    name: 'Marc',
})

watchEffect(() => {
    console.log('👻 state changed', state.count, state.name)
})

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

setTimeout(() => {
    state.count++
}, 2000)
setTimeout(() => {
    state.count++
}, 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](https://gist.github.com/themarcba/618264a12f277f10570c30759c592546).

# 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

*Original cover photo by [Joshua Earle](https://unsplash.com/@joshuaearle?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on Unplash, edited by [Marc Backes](https://marc.dev/).*