Computed properties are reactive, cached values derived from other reactive data. They automatically re-evaluate only when their dependencies change - unlike methods, which re-run on every render.
| Feature | Computed | Method | Watch |
|---|---|---|---|
| Cached | Yes - only recalculates when deps change | No - runs every render | N/A |
| Returns value | Yes | Yes | No (side effects) |
| Async support | No | Yes | Yes |
| Best for | Derived data, filtering, formatting | Event handlers, actions | Side effects, async ops |
<template>
<div>
<p>Full name: {{ fullName }}</p>
<p>Reversed: {{ reversedMessage }}</p>
<p>Active users: {{ activeCount }}</p>
<!-- Writable computed -->
<input v-model="fullNameWritable" placeholder="First Last" />
<p>First: {{ firstName }}, Last: {{ lastName }}</p>
<!-- Computed vs method - same result, different performance -->
<p>Computed (cached): {{ expensiveComputed }}</p>
<p>Method (not cached): {{ expensiveMethod() }}</p>
</div>
</template>
<script setup>
import { ref, reactive, computed } from 'vue'
const firstName = ref('Alice')
const lastName = ref('Smith')
const message = ref('Hello Vue!')
const users = reactive([
{ id: 1, name: 'Alice', active: true },
{ id: 2, name: 'Bob', active: false },
{ id: 3, name: 'Carol', active: true },
])
// Read-only computed
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
const reversedMessage = computed(() => message.value.split('').reverse().join(''))
const activeCount = computed(() => users.filter(u => u.active).length)
// Writable computed - get + set
const fullNameWritable = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (val) => {
const parts = val.trim().split(' ')
firstName.value = parts[0] || ''
lastName.value = parts.slice(1).join(' ') || ''
}
})
// Expensive computation - computed caches the result
const expensiveComputed = computed(() => {
console.log('Computing...') // only runs when users changes
return users.reduce((sum, u) => sum + u.name.length, 0)
})
// Method - runs on every render
function expensiveMethod() {
console.log('Method called...') // runs every time template re-renders
return users.reduce((sum, u) => sum + u.name.length, 0)
}
</script>
<template>
<div class="cart">
<div v-for="item in cart" :key="item.id" class="cart-item">
<span>{{ item.name }}</span>
<input type="number" v-model.number="item.qty" min="1" />
<span>${{ (item.price * item.qty).toFixed(2) }}</span>
<button @click="removeItem(item.id)">Remove</button>
</div>
<div class="cart-summary">
<p>Items: {{ totalItems }}</p>
<p>Subtotal: ${{ subtotal }}</p>
<p v-if="hasDiscount">Discount (10%): -${{ discount }}</p>
<p><strong>Total: ${{ total }}</strong></p>
<p v-if="freeShipping" class="success">Free shipping!</p>
<p v-else>Add ${{ shippingThreshold - subtotal }} more for free shipping</p>
</div>
</div>
</template>
<script setup>
import { reactive, computed } from 'vue'
const cart = reactive([
{ id: 1, name: 'Vue T-Shirt', price: 25.00, qty: 2 },
{ id: 2, name: 'Vue Mug', price: 15.00, qty: 1 },
{ id: 3, name: 'Vue Sticker', price: 5.00, qty: 3 },
])
const shippingThreshold = 50
const totalItems = computed(() => cart.reduce((sum, i) => sum + i.qty, 0))
const subtotal = computed(() => cart.reduce((sum, i) => sum + i.price * i.qty, 0).toFixed(2))
const hasDiscount = computed(() => Number(subtotal.value) >= 100)
const discount = computed(() => (Number(subtotal.value) * 0.1).toFixed(2))
const total = computed(() => (Number(subtotal.value) - (hasDiscount.value ? Number(discount.value) : 0)).toFixed(2))
const freeShipping = computed(() => Number(subtotal.value) >= shippingThreshold)
function removeItem(id) {
const idx = cart.findIndex(i => i.id === id)
if (idx !== -1) cart.splice(idx, 1)
}
</script>
Vue records reactive values read while a computed getter runs. The result is reused until one of those dependencies changes. Non-reactive values such as Date.now do not invalidate the cache, and a branch that was not read does not become a dependency for that evaluation.
Use computed for pure derived state, a method when each call should perform the calculation again, and watch for a side effect such as persistence or a request. Mutating state inside a computed getter can create feedback and makes evaluation timing difficult to predict.
A writable computed property supplies get and set. The setter should translate an assigned view value into deliberate source-state updates; it should not silently discard information or trigger unrelated effects. Test both directions and invalid assignments before using it as a v-model boundary.
A computed property tracks reactive reads that happen while its getter runs. If a value is pulled out of a reactive object into a plain variable, the getter may no longer read the reactive source. Use refs, toRefs, or access the reactive object inside the computed getter.
Use a writable computed when the value is a two-way view of other state, such as a formatted input that reads from one value and writes a normalized value back.
Computed values are cached, but they still recalculate whenever one of their tracked dependencies changes.
Explore 500+ free tutorials across 20+ languages and frameworks.