Cansu Arı Logo
Blog
What is it?

Computed or Watch? When to Use Which

In Vue’s reactivity system, computed and watch may look similar but serve fundamentally different purposes.

  • #Vue.js

Skip to content

Computed or Watch?

Vue’s reactivity system has two core players: computed and watch. Both respond to data changes, but they don’t do the same job. Using the wrong one can cause unnecessary renders or unexpected behavior.

This post explains their differences, the right usage scenarios, and performance considerations.

Computed: Reactive Calculation Field

computed is for creating derived state—results that are automatically computed from one or more reactive sources.
import { ref, computed } from 'vue'

const firstName = ref('Cansu')
const lastName = ref('Arı')
const fullName = computed(() => `${firstName.value} ${lastName.value}`)

Here, fullName updates whenever firstName or lastName changes. Vue tracks the computed function and recalculates only when dependencies change; otherwise it uses the cache.

Summary: Use computed when you’ll display a value in the DOM that comes from a calculation you control.

Watch: Side-Effect Listener

watch observes one or more reactive sources and runs a callback when they change. The goal isn’t to compute, but to react.
import { ref, watch } from 'vue'

const age = ref(20)

watch(age, (newVal, oldVal) => {
console.log(`Age changed: ${oldVal} → ${newVal}`)
if (newVal >= 35) alert('You’re not that young anymore 😛')
})

This is handy for API calls, updating localStorage, or kicking off an animation.

Warning: Don’t use watch to provide a value for the template. A watcher doesn’t return a value; it defines a reaction.

Key Differences

PropertyComputedWatch
PurposeCompute derived valueRun side effects
Return valueYes (via return)No (callback-based)
CachingYesNo
Triggers re-render?Indirectly, via its valueNo; you act manually
Typical usefullName, filteredListAPI calls, logging, sync

Advanced: watchEffect

Introduced in Vue 3, watchEffect sits between computed and watch. It automatically tracks any reactive values used inside.
import { ref, watchEffect } from 'vue'

const count = ref(0)
watchEffect(() => {
console.log('Count changed:', count.value)
})

If you want reactive tracking without specifying dependencies, watchEffect is great. But because it can run after each render, use it carefully.

It’s typically used for data loading or “auto-reaction” flows that need cleanup.

watch vs watchEffect

PropertywatchwatchEffect
DependenciesManualAuto-detected
First runOn changeImmediately
PerformanceMore controlledCan trigger more often
Use caseAPI, side effectsSimple dependency tracking

Performance & Best Practices

  • Never perform side effects (like fetch) inside computed; computed is only for producing values.
  • watch may fire frequently—use debounce/throttle where needed.
  • To deeply observe a reactive object, use deep: true:
watch(() => user.value, handler, { deep: true })
Only use deep watching when necessary—it can hurt performance.

Which One When?

ScenarioUse
Derived value to display in the templatecomputed
Calculation tied to user typingcomputed
Making an API callwatch or watchEffect
Syncing with localStoragewatch
Triggering animation/scroll on reactive changewatch
Simple console.log or transient reactionwatchEffect

Real-World Example

A filtering scenario:
const query = ref('')
const items = ref(['vue', 'react', 'svelte'])
const filtered = computed(() => items.value.filter(i => i.includes(query.value)))
computed drives what the DOM shows. But if you must call an API based on that change:
watch(query, debounce(fetchResults, 500))
That’s where watch comes in. One controls what the UI shows; the other controls what happens outside the UI.

Conclusion

The difference between computed and watch goes deeper than it seems. computed computes a value, while watch reacts to a change. Use them correctly to avoid unnecessary renders and to keep your code readable.

In short: computed transforms data; watch transforms behavior.

All tags
  • Vue.js