Skip to content

Vue Computed Properties

Expressions in templates are very convenient, but they are designed for simple operations. Putting too much logic in templates makes them bloated and hard to maintain. For any complex logic involving reactive data, you should use computed properties.

Basic Example

Imagine we have a reactive object author with two properties: name and books. We want to display different messages based on whether author has books.

vue
<script setup>
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 ref
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})
</script>

<template>
  <p>Has published books:</p>
  <span>{{ publishedBooksMessage }}</span>
</template>

Here, we defined a computed property publishedBooksMessage. The computed() function accepts a getter function as a parameter, and its return value is a computed property ref. Similar to other refs, you can access its computed result via .value.

Vue's computed properties automatically track their reactive dependencies. It detects that publishedBooksMessage depends on author.books. Therefore, when author.books changes, any binding that depends on publishedBooksMessage will update automatically.

Computed Property Caching vs. Methods

You may notice that we can achieve the same effect by calling a method in an expression:

vue
<!-- Call a method in the template -->
<p>{{ calculateBooksMessage() }}</p>
js
// In the component
function calculateBooksMessage() {
  return author.books.length > 0 ? 'Yes' : 'No'
}

For the final result, both approaches are indeed the same. However, the difference is that computed properties are cached based on their reactive dependencies.

A computed property will only re-evaluate when its relevant dependencies change. This means that as long as author.books doesn't change, multiple accesses to publishedBooksMessage will immediately return the previously computed result and will not execute the function again.

In contrast, whenever a re-render is triggered, the method will always execute the function again.

Why is caching needed? Suppose we have a computationally expensive computed property list that needs to traverse a huge array and do a lot of calculations. Then we might have other computed properties that depend on list. Without caching, we would unavoidably execute list's getter multiple times! If you don't want caching, please use methods instead.

Writable Computed Properties

Computed properties are read-only by default. When you try to modify a computed property, you'll receive a runtime warning. Only in certain special scenarios might you need a "writable" computed property, in which case you can create one by providing both getter and setter:

vue
<script setup>
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) {
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})

// Now, when you run `fullName.value = 'Jane Smith'`,
// the setter will be called, and firstName and lastName will be updated accordingly.
</script>

Best Practices

  • Getters Should Have No Side Effects: It's very important that computed property getters should only perform calculations and have no other side effects. For example, don't make async requests or modify the DOM in a getter!

  • Avoid Directly Modifying Computed Property Values: Values returned from computed properties are derived state. You can think of them as a "temporary snapshot"; whenever source state changes, a new snapshot is created. Changing the snapshot makes no sense, therefore the return value of a computed property should be treated as read-only and should never be modified—you should update the source state it depends on to trigger a new calculation.

Content is for learning and research only.