Computed Properties in Vue
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.