Computed Properties
A computed property is a reactive value derived from other reactive state. Internally, it is actually a function whose output is cached and returned on subsequent calls. They are useful to avoid computationally expensive methods being called more often than necessary.
import { reactive, computed } from 'vue'
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
// a computed property
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})A computed property automatically tracks its reactive dependencies. In the example above, Vue is aware that the computation of publishedBooksMessage depends on author.books, so the computed() function is re-run every time author.books changes and re-cached.
The computed() function expects a getter function. The example above uses the shorthand form, but it can be written using the object syntax as follows:
// a computed property
const publishedBooksMessage = computed({
get() => {
return author.books.length > 0 ? 'Yes' : 'No'
}
})The returned value of computed() is a computed ref. And Similar to normal refs, you can access the computed result using .value property. Computed refs are also auto-unwrapped in templates just like normal refs so you can reference them without .value in template expressions.
Computed Caching vs Methods
Instead of using a computed property, you could implement the same logic as a method. In terms of the end result, the two approaches are indeed exactly the same. However, the difference is that computed properties are cached based on their reactive dependencies. A computed property will only re-evaluate when one of its reactive dependencies changes.
For example, the following computed property will never update, because Date.now() is not a reactive dependency:
const now = computed(() => Date.now())In contrast, a method runs every time it is called, which typically means on every component re-render.
Caching prevents unnecessary recomputation by ensuring that a computed property only re-evaluates when its reactive dependencies change. This improves performance during frequent re-renders, avoids repeating expensive calculations, and ensures that derived state remains predictable and efficient, especially when the same value is used multiple times within a component.
Writable Computed
Computed properties are by default getter-only. If you attempt to assign a new value to a computed property, you will receive a runtime warning. In the rare cases where you need a "writable" computed property, you can create one by providing both a getter and a setter:
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
// getter
get() {
return firstName.value + ' ' + lastName.value
},
// setter
set(newValue) {
// Note: we are using destructuring assignment syntax here.
[firstName.value, lastName.value] = newValue.split(' ')
}
})Now when you run fullName.value = 'John Doe', the setter will be invoked and firstName and lastName will be updated accordingly.
Getting the Previous Value
NOTE
This feature is only available in Vue 3.4 and above.
In case you need it, you can get the previous value returned by the computed property accessing the first argument of the getter:
import { ref, computed } from 'vue'
const count = ref(2)
// This computed will return the value of count when it's less or equal to 3.
// When count >= 4, returns the previous computed value instead.
const alwaysSmall = computed((previous) => {
if (count.value <= 3) {
return count.value
}
return previous
})In case you're using a writable computed:
import { ref, computed } from 'vue'
const count = ref(2)
const alwaysSmall = computed({
get(previous) {
if (count.value <= 3) {
return count.value
}
return previous
},
set(newValue) {
count.value = newValue * 2
}
})Best Practices
Getters should be side-effect free
It is important to remember that computed getter functions should only perform pure computation and be free of side effects. For example, don't mutate other state, make async requests, or mutate the DOM inside a computed getter! Think of a computed property as declaratively describing how to derive a value based on other values - its only responsibility should be computing and returning that value.
Avoid mutating computed value
The returned value from a computed property is derived state. Think of it as a temporary snapshot - every time the source state changes, a new snapshot is created. It does not make sense to mutate a snapshot, so a computed return value should be treated as read-only and never be mutated - instead, update the source state it depends on to trigger new computations.
