Computed Properties
|
This section documents the current Vue 3.x release line as published at
the official Vue.js documentation, which is the reference these pages are written and
verified against. No specific patch version is pinned. The Composition API with This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production, since Vue and its ecosystem iterate quickly. This section’s bibliography lists the reference material consulted while preparing these pages. |
A computed property is a reactive value derived from other reactive state. You give computed() a getter;
it returns a ref whose .value is the getter’s result, recomputed only when a dependency changes. This page
follows Computed Properties and the
computed() API entry.
The basics
<script setup>
import { ref, computed } from 'vue'
const first = ref('Ada')
const last = ref('Lovelace')
const fullName = computed(() => `${first.value} ${last.value}`)
</script>
<template>
<p>{{ fullName }}</p> <!-- auto-unwrapped, like any ref -->
</template>
In the template fullName behaves like the other refs. In script you read fullName.value.
Caching vs. a method
A computed property caches. Its getter re-runs only when one of the reactive values it read last time changes; any number of reads in between return the stored result. A method, by contrast, runs on every re-render, because the template has no way to know whether its result would differ.
<script setup>
import { ref, computed } from 'vue'
const list = ref([1, 2, 3, 4, 5, 6])
// cached: recomputed only when `list` changes
const evens = computed(() => list.value.filter((n) => n % 2 === 0))
// not cached: runs on every render that calls it
function evensNow() {
return list.value.filter((n) => n % 2 === 0)
}
</script>
For an expensive derivation — filtering a large array, formatting dates, walking a tree — the cache is the
whole point. computed also does not recompute when an unrelated piece of state triggers the re-render.
When a method is the right choice
Use a method (or a plain function) instead of computed when:
-
the result takes arguments —
formatPrice(item)in av-for; a computed takes none; -
you want it to run every time on purpose, e.g.
Date.now()orMath.random(), which have no reactive dependency to cache against; -
it performs an action rather than producing a value — see Reactivity Fundamentals and
watchfor side effects.
Writable computed
Pass an object with get and set to make a computed assignable. The setter runs when code writes
.value, and typically writes back to the underlying refs.
<script setup>
import { ref, computed } from 'vue'
const first = ref('Ada')
const last = ref('Lovelace')
const fullName = computed({
get() {
return `${first.value} ${last.value}`
},
set(value) {
[first.value, last.value] = value.split(' ')
},
})
fullName.value = 'Grace Hopper' // runs set(); first -> 'Grace', last -> 'Hopper'
</script>
Keep getters pure
A getter must only compute and return. Do not mutate other reactive state, perform async requests, or
touch the DOM inside it — those make the value unpredictable and can loop. Put effects in watch or
watchEffect. It is also fine to return a fresh object or array from a getter; since 3.4 Vue compares the
getter’s result and skips downstream updates when it is deeply unchanged from the previous run, so a stable
value does not cause needless re-renders.
computed vs. watch
Both react to state, but they answer different questions:
Use computed when |
Use watch / watchEffect when |
|---|---|
you need a value that is a pure function of other state |
you need a side effect — fetch data, write to |
the template or other logic reads the result |
nothing reads a result; you are reacting, not deriving |
Reaching for watch to copy one ref into another is almost always a computed in disguise. See
Reactivity Fundamentals for watch.
Debugging a computed
For development, computed() accepts onTrack and onTrigger hooks as a second (or, with the object form,
extra) argument. onTrack fires when a dependency is collected; onTrigger fires when a dependency change
schedules the recompute. Both receive a DebuggerEvent you can log or debugger-break on.
import { computed } from 'vue'
const total = computed(
() => items.value.reduce((sum, i) => sum + i.price, 0),
{
onTrack(e) {
// e.target, e.type, e.key -- which dependency was read
console.log('tracked', e)
},
onTrigger(e) {
// e.oldValue, e.newValue -- what changed
debugger
},
},
)
These hooks are stripped from production builds. The advanced debugging APIs are listed under
computed() and
Reactivity Fundamentals.
See also
-
Reactivity Fundamentals —
ref,reactive, andwatch/watchEffect. -
Template Syntax — where a computed’s value is read in bindings.
-
Conditional and List Rendering — a common home for a computed that filters a list.