Reactivity in Vue.js 2 vs Vue.js 3

The Vue.js core team has already discussed the changes that will be implemented in Vue 3. While the API will not be changing, the reactivity mechanism will be different. What does this mean, and what does it mean to you?


Vue 2 Reactivity

Reactivity in Vue.js is accomplished through getters and setters as defined in the Object.defineProperty method. Let’s make a watered down version of what’s happening in Vue.

Object.defineProperty(obj, key, {      
    enumerable: true,  
    configurable: true,  
    get(){  
       return value;  
    },  
    set(newValue){  
        if(value !== newValue){  
           value = newValue;  
           tellTheWorldIhaveChanged(); //somebody is watching!  
        }  
    }  
});

Using this type of setup, every time we make a change to the property, it notifies watchers and dependencies that need to know that there has been a change. This property setup is what happens on initialization of our model and when we explicitly call Vue.set/vm.$set.

With this setup, however, the following requires extra help:

  1. Array updates by index
data(){  
  return {  
    names:[]  
  }  
}  

this.persons[0] = 'John Elway';

You are probably aware that this will not trigger an update. In fact, the holy guide of Vue explicitly mentions caveats to arrays. Why is this so? Because setters on arrays have no means of detecting assignments by index.

One option to handle this is to use Vue.set

Vue.set(this.names, 0, 'John Elway');

However, Vue is kind enough to wrap a few array methods for us, so we can update our arrays using those array methods.

this.names.push('John Elway');

2. Adding properties dynamically

data(){  
  return {  
    names:[]  
  }  
}


this.$data.lastAddedName = 'John Elway';

Not the best example, right? I probably should have already knew that this property would exist, but there are cases that we might not know the property name. JavaScript loosed-typedness allows us to add properties with ease. Vue reactivity, however, has no clue that we added this property.

Here I come to save the day! — Vue.set

Vue.set(this.$data,'lastAddedName','John Elway');

If only we had a way to avoid all this Vue.set usage and give ourselves back the array indexes.

Vue 3 Reactivity

Welcome to the world of reactivity through proxies. Proxies are a feature introduced in ES6 AKA ES2015 AKA they’ve been out for a while. Because of that, I’m sure you have learned about them, but may have not been able to use them in a production environment because they’re unshimmable. No polyfill and no way to fake them in older browsers.

Fortunately, the syntax is not absurd. In fact, it’s somewhat familiar.

let data = {  
   names:[]  
};

data.names = new Proxy(data.names,{  
    set(obj, prop, value){  
        if(obj[prop] !== value){  
            obj[prop] = value;  
            tellTheWorldIhaveChanged();  
        }  
    }  
});

Not only will this proxy catch the indexed array placement we mentioned earlier, but it will also fire when the array methods are called. No wrappers needed.

What about adding properties dynamically?

data = new Proxy(data,{  
    set(obj, prop, value){  
        if(obj[prop] !== value){  
            obj[prop] = value;  
            tellTheWorldIhaveChanged();  
        }  
    }  
});

data.lastAddedName = 'John Elway'; //tellTheWorldIhaveChanged()

OMG, this is so awesome. Let’s create a petition on Change.org for a fast release!


Summary

I’m typing this shortly before the release of 2.5. Vue 3 hasn’t been talked about a whole lot, but I am really looking forward to it due to the changes mentioned above. That being said, I won’t be able to use it on work projects for the immediate future. Why? Vue 3 cannot be used with Internet Explorer and Babel’s not going to be able to fix that.

There are a few long term advantages to this rewrite though.

  1. Simplification of the source — This rewrite allow the team to nix the array function wrappers and reduce the amount of type checking they are doing
  2. Easier for newcomers to learn — Taking the caveats out of the reactivity will help those new to Vue. This will eliminate a whole class of issues on the forums.
  3. Better performance* — I’ve seen some folks suggest that this will speed up the reactivity system. It’s already pretty fast, and I haven’t quite been sold on this point

Thanks for reading! If you notice any mistakes, please let me know.

Update

It appears that the version using proxies will be appending -next (like esnext) , to the current version instead of “Vue 3”. This update may come as early as Vue 2.6. So, when that comes out, there will be a distro for Vue 2.6 and Vue 2.6-next. This should eliminate confusion about what’s available in the API.

You may also like