preloader

The latest generation of frontend frameworks brings us the possibility to take better care of users and provide them with the best possible user experience (UX). In order to do so, we ought to keep our users with the latest available data. A problem that arises is how to detect changes and display them in real-time. In the pool of many options, it is important to maintain the simplicity-flexibility ratio on the expected level. VueJS stands out as one of the simplest, yet quite flexible framework

Keeping the data updated

Providing users with top-quality UX requires a smooth change detection algorithm and seamless layout updates. Featuring two-way binding, VueJS provides us with high performance and easy data flow. Another thing being featured is virtual DOM – a smarter and more efficient little brother of the traditional HTML DOM.

How does this work?

One of the ways to keep the data updated everywhere is two-way data binding by using the v-model directive. Let’s explain how this works on a basic code example:

<div id=”app”>
  <input v-model=”myValue” type=”number”>
</div>
let vm = new Vue({
  data: {
    myValue: 1,
    myObject: {},
    myArray: []
  },
  methods: {
    changeValue() {
      this.myValue = 2;
    }
  }
})

The value in the input field will automatically be set to 1. If a user makes a change, it will be automatically propagated to the myValue property. When a changeValue method is invoked, the value of myValue property will be changed to 2, which will be immediately visible on the UI.

When the Vue instance is created, it automatically builds a virtual DOM tree based on the initially given data and dependent components. Each Vue instance has at least one component. If the data option of a Vue component is a plain JavaScript (JS) object, Vue will create appropriate getters and setters for all its properties. These properties are considered to be reactive, and their implicit simple getters and setters are part of the default Vue change detection algorithm. Any occurring change will invoke the setter function, which will eventually trigger the component to re-render and re-generate its virtual DOM, which will, in turn, through various diffing algorithms, update only the relevant part(s) of the HTML DOM.

When this isn’t working?

Unfortunately, there are cases when this approach isn’t the best. According to VueJS official documentation, Vue cannot detect deletion and addition which would mean that it is not possible to add new reactive properties to objects with simple assigning of value. Also, it is not possible to add new root-level reactive properties

//Neither of this will be reactive
this.myNewValue = 1; //new root-level property
this.myObject.someProperty = 1; //new nested object property
this.myObject[‘someProperty’] = 1; //new nested object property
this.myArray[0] = 1; //new nested array element

In order to make new reactive properties, we ought to use a method dedicated to such a purpose

Vue.set(object, property, value) 

Invocation of this method will make property reactive.

Each Vue instance also has $set method, which is syntactic sugar for the previously mentioned method
this.$set(object, property, value)

//All will make the property reactive
Vue.set(this.myObject, ‘someProperty’, 1);
this.$set(this.myObject, ‘someProperty’, 1);

When it comes to arrays, we should treat them as any other object. Instead of the property name, an element index needs to be provided

this.$set(this.myArray, 0, 1);

Of course, arrays have additional methods, like push, slice, splice… which will also make the magic happen.

If there is a need to assign multiple reactive properties, they can be added one-by-one using the explained process if all properties are known. On the other hand, when the set of new properties is unknown, it is recommended to use the universal approach:
Create a new object and replace the old one with it

//Object b holds all properties which should be added
this.myObject = Object.assign({}, this.myObject, b);

The reasons for replacement are following:

  1. Object.assign() and other similar methods will not invoke Vue.set() method, making all further changes irrelevant and ignored
  2. Replacement will not replace the value only, but the reference too, which will invoke component re-rendering
  3. If a “property of a property” has changed, this might not be detected

Combination of Vue.set and object replacement will also result in expected behavior

this.$set(this, ‘myObject’, Object.assign({}, this.myObject, b))

Conclusion

With current limitations, both from VueJS and Javascript itself, the safest way to ensure all changes are visible and detectable is to anticipate all possible properties in advance and declare them before Vue instance is created and use dedicated Vue methods to apply those changes, especially when there is a need to add a new property.
In addition to that, make sure that object-like values (objects, arrays, etc.) are always updated by using embedded reactive methods or by plain reference replacement.

The written is valid for Vue.js 2.