Computed Properties in Vue

Jul 15, 2019

In Vue, computed properties help you avoid putting too much logic in your template expressions. For example, suppose your app has a list of reviews, and you want to display the average of all reviews.

const app = new Vue({
  data: () => ({
    reviews: [
      { score: 5 },
      { score: 3 },
      { score: 4 }
    ]
  }),
  // Computing the average in a template expression is awkward
  template: `
    <div>
      {{reviews.reduce((sum, v) => sum + v.score, 0) / reviews.length}} ({{reviews.length}} reviews)
    </div>
  `
});

Instead of computing the average in the template, you can instead create a computed property average, and use average in the template expression instead.

const app = new Vue({
  data: () => ({
    reviews: [
      { score: 5 },
      { score: 3 },
      { score: 4 }
    ]
  }),
  computed: {
    // `average` is a computed property. Vue will call `computeAverage()`
    // for you when a `data` property changes.
    average: function computeAverage() {
      if (this.reviews.length === 0) {
        return 0;
      }
      return this.reviews.
        reduce((sum, v) => sum + v.score, 0) / this.reviews.length;
    }
  },
  template: `
    <div>
      {{average}} ({{reviews.length}} reviews)
    </div>
  `
});

When To Use Computed Properties Versus Methods

You can also use Vue methods to abstract out complex template logic as shown below.

const app = new Vue({
  data: () => ({
    reviews: [
      { score: 5 },
      { score: 3 },
      { score: 4 }
    ]
  }),
  methods: {
    // `average` is a method that's called in the template expression
    average: function average() {
      if (this.reviews.length === 0) {
        return 0;
      }
      return this.reviews.
        reduce((sum, v) => sum + v.score, 0) / this.reviews.length;
    }
  },
  template: `
    <div>
      {{average()}} ({{reviews.length}} reviews)
    </div>
  `
});

Both approaches work, but Vue caches computed properties based on their "reactive values". In other words, Vue figures out what data fields your computed property relies on, and doesn't recompute the computed property unless one of those data fields changes.

For example, if you have a computed property that only depends on field1, Vue won't recompute the property if you modify field2.

const app = new Vue({
  data: () => ({
    field1: 'row',
    field2: 'your boat'
  }),
  computed: {
    // Vue will **only** call` getter()` when `field2` changes. Vue will
    // not call `getter()` when `field1` changes.
    field2Upper: function getter() {
      console.log('Called!');
      return this.field2.toUpperCase();
    }
  },
  template: `
    <div>
      <div>
        {{field1}} {{field2Upper.toLowerCase()}}
      </div>
      <button v-on:click="field1 += ' row'">Add</button>
    </div>
  `
});

If your computed property is expensive, computed properties can save you from unnecessarily recalculating. Vue has a clever algorithm for tracking what properties your computed property depends on. When the function getter() above accesses field2, Vue intercepts that property access and adds it to a list of fields getter() depends on.


More Vue Tutorials