Computed properties

Vue · Essentials · 9 min

Derived values belong in computed properties, not in duplicated state or expensive template expressions.

A computed property derives a value from other reactive state:

const remaining = computed(() => todos.value.filter(t => !t.done).length)

computed() returns a read-only ref, so in script you read remaining.value and in the template simply {{ remaining }}.

Two properties make computeds better than calling a function in the template:

  • Dependency tracking: Vue records which reactive values the getter read and recomputes only when one of them changes.
  • Caching: reading it repeatedly returns the cached value; a method would re-run on every render.

Keep getters pure: no fetching, no mutating other state, no DOM access. Side effects belong in watchers. Also never mutate the computed result (for example sorting it in place); treat it as a snapshot.

For the rare two-way case, pass get and set to make a writable computed, for example a fullName that splits back into first and last names.

Since Vue 3.4 a computed only notifies dependents when its value actually changes, so const isEven = computed(() => n.value % 2 === 0) does not re-render consumers when n goes from 2 to 4.

A common smell is copying derived data into a ref and keeping it in sync with a watcher. If a value can be computed from existing state, make it a computed.

Example

import { ref, computed } from 'vue'

const todos = ref([
  { text: 'Read docs', done: true },
  { text: 'Build app', done: false },
])
const remaining = computed(() => todos.value.filter(t => !t.done).length)
console.log(remaining.value)         // 1
todos.value.push({ text: 'Ship', done: false })
console.log(remaining.value)         // 2 (recomputed lazily on read)

const first = ref('Ada'), last = ref('Lovelace')
const fullName = computed({
  get: () => `${first.value} ${last.value}`,
  set: (v) => { [first.value, last.value] = v.split(' ') },
})
fullName.value = 'Grace Hopper'
console.log(first.value)            // Grace

Remember

  • computed(() => ...) returns a cached, read-only ref
  • It recomputes only when a reactive dependency changes
  • Keep getters pure; use get/set only when two-way derivation is needed

Watch out for

  • Mutating inside a getter, such as list.value.sort(), which changes the source state.

Check yourself

  1. A template shows `{{ total }}` three times, where total is a computed over a large array. How many times does the getter run per render if nothing changed?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: vuejs.org/guide/essentials/computed.html