DEV Community

Cover image for Vue.js Computed Properties in Depth
James Sinkala
James Sinkala

Posted on • Originally published at vuenoob.com

Vue.js Computed Properties in Depth

As we learned in the previous post, Vue.js computed properties help us de-clutter complex template expressions and help make our code readable and maintainable.
That's the gist of it, we are going to have an in-depth look into them inside this post.

To help us along, let's create a new Vue.js app.

<div id="app">
  <p> {{ personalInfo }} </p>
</div>

<script src="https://unpkg.com/vue@3"></script>
<script>
  let app = Vue.createApp({
    data: function () {
      return {
        firstName: 'Vue',
        lastName: 'Noob',
        age: 21,
        locality: 'Vueland',
      };
    },
    computed: {
      personalInfo(){
        return `My name is ${this.firstName} ${this.lastName}, I am ${this.age} years old. I am based in ${this.locality}.`;
      }
    }
  }).mount('#app');
</script>
Enter fullscreen mode Exit fullscreen mode

Reactivity in Computed Properties

Computed properties do observe changes in all of their dependencies and update accordingly. In the above instance, the personalInfo computed property observes the changes in the firstName, lastName, age, and locality variables, when it detects changes in any of their values it updates itself to reflect the changes.

Try changing the values of those variables to see the results.

Caching in Computed Properties

One essential feature that computed properties have is caching, this is an advantage that computed properties have over methods, a Vue.js property that will be covered later.

The gist on caching in Vue.js computed properties is that, when a computed property has been resolved, Vue.js caches that resulting value, when new references are made to this computed property, the cached value is returned instead of re-running the expressions inside in the computed property. Re-running of contained expression happens in the case of methods.

Computed properties will only re-evaluate when one of their dependencies have changed.
This is an important characteristic as it helps save on physical resources, especially when running complex expressions that require a lot of computations. This is more so when apps grow and the codebase becomes bigger.

Computed Properties Shortcomings

While computed properties caching is sound it does fall short in some cases, copy and run the following modification to our last example.

<div id="app">
  <p> {{ personalInfo }} </p>
+ <p> {{ morePersonalInfo }} </p>
+ <p> {{ morePersonalInfoDelayed }} </p>
</div>

<script src="https://unpkg.com/vue@3"></script>
<script>
  let app = Vue.createApp({
    data: function () {
      return {
        firstName: 'vue',
        lastName: 'noob',
        age: 21,
        locality: 'Vueland',
+       time: Date.now(),
+       morePersonalInfoDelayed: ''
      };
    },
    computed: {
      personalInfo(){
        return `My name is ${this.firstName} ${this.lastName}, I am ${this.age} years old. I am based in ${this.locality}.`;
      },
+      morePersonalInfo(){
+       return `I'll be travelling on ${new Date(this.time).toUTCString()}.`;
+     }
    },
+   mounted(){
+     setTimeout(() => {
+       this.morePersonalInfoDelayed = this.morePersonalInfo;
+     }, 5000);
+   }
  }).mount('#app');
</script>
Enter fullscreen mode Exit fullscreen mode

The mounted() function in the above example is a lifecycle hook, a topic that will be covered later.

In our example, you'll notice that both computed properties morePersonalInfo and morePersonalInfoDelayed give us the same string despite morePersonalInfoDelayed being resolved 5 seconds later. This is where computed properties fall short, when dealing with non-reactive dependencies such as Date.now() and Math.random().
In such cases using methods is the proper way to go about it.

Customizing Computed Properties

Computed properties are by characteristic getter-only, i.e. we only expect to get values from them and should not be assigning values to them.
Mutating or assigning values to computed properties is futile since the value obtained from them is a temporary snapshot of the state and is subject to change when its dependencies change, a feature we target to make use of when using them in the first place.
Also trying to do this will trigger a run-time warning.

In the few cases where the need to manually customize computed properties behavior, we can do so by providing getters and setters.

Observe the following example.

<div id="app2">
  <p> {{ priceOfAnItem }} </p>
</div>

<script src="https://unpkg.com/vue@3"></script>
<script>
  let app2 = Vue.createApp({
    data: function () {
      return {
        item: 'Apple',
        price: '2'
      };
    },
    computed: {
      priceOfAnItem: {
        get(){
          return `One ${this.item} costs ${this.price} dollars`;
        },
        set(resolvedVal){
          [,this.item,,this.price,] = resolvedVal.split(' ');
        }
      }
    },
    mounted(){
      setTimeout(() => {
        this.priceOfAnItem = `One Orange costs 5 dollars`;
      }, 3000);
    }
  }).mount('#app2');
</script>
Enter fullscreen mode Exit fullscreen mode

If you run the above example you'll see that after 3 seconds the item and price values change to "Orange" and 5 respectively, that happens after we update the value of the computed property with help from the setter.

Updating the computed property this way frees us from experiencing a run-time warning and unexpected results in our app.

It is advised to use getter functions to only perform pure computations and avoid handling side-effect creating activities such as making function and DOM altering calls, such side-effect making logic can be performed inside Vue.js watchers.

The source code to the examples in this post are found in this file.

Top comments (0)