⚡New: We've launched a brand new Coding Challenges section! Check out these interactive, real-world exercises to level up your skills.Explore Challenges→
Master when to use computed properties versus watchers in Vue. Understand caching, dependency tracking, asynchronous operations, and best practices for side-effects.
While both computed properties and watchers respond to changes in reactive data, they are designed for completely different use cases. Choosing the wrong one can lead to performance issues, dirty state tracking, and redundant component updates.
1. What the Interviewer Is Testing
Interviewers want to see if you understand:
The Caching Layer: How does Vue avoid re-evaluating computed properties on every render?
Synchronous vs Asynchronous Operations: Why can't computed properties perform fetch calls or set timeouts?
Side-Effects vs Pure Transformations: Which one represents pure state transformations and which one handles side-effects?
Deep Tracking Overhead: What are the performance costs of setting { deep: true } in a watcher?
2. Computed Properties: Pure Declarative State
A computed property is a declarative, derived value that automatically tracks its reactive dependencies and caches the result.
Key Rules of Computed Properties
Dependency Caching: A computed property will only re-evaluate when at least one of its active reactive dependencies changes. If the dependencies haven't changed, accessing the computed property returns the cached value instantly without running the getter function again.
No Side-Effects: Computed getters must be pure functions. They should only calculate and return a new value. They must never modify external state, trigger API calls, or mutate other reactive properties.
Synchronous: The getter must run synchronously to calculate the return value immediately.
import { ref, computed } from 'vue'const price = ref(100)const quantity = ref(2)// Tracks price and quantity, caches resultconst total = computed(() => { return price.value * quantity.value})
3. Watchers: Imperative Side-Effects
A watcher (watch or watchEffect) is an imperative hook that executes a callback function whenever a reactive dependency changes.
Key Rules of Watchers
Supports Asynchronous Work: Watchers are ideal for executing asynchronous operations, such as calling an external API, performing search debouncing, or setting timeouts.
Side-Effects Permitted: Unlike computed properties, watchers are designed specifically for side-effects (e.g. updating the local storage, manipulating the DOM, or fetching network resources).
Before/After Values: The callback receives both the new value and the old value of the tracked target.
import { ref, watch } from 'vue'const searchQuery = ref('')const apiResults = ref([])watch(searchQuery, async (newQuery, oldQuery) => { if (newQuery.length < 3) return // Asynchronous side-effect is totally fine here apiResults.value = await fetchSearchData(newQuery)})
4. Computed vs Watcher: Head-to-Head
Feature
Computed Properties
Watchers
Purpose
Transform/derive data from other state.
Perform side-effects when state changes.
Execution
Synchronous and pure.
Synchronous or Asynchronous; side-effects allowed.
Caching
Yes (returns cached value unless dependencies change).
No (executes callback on every state mutation).
Returns Value
Yes (must return a value).
No (returns nothing; mutations are done imperatively).
Access to Old Value
No.
Yes (receives newVal and oldVal parameters).
5. Performance Gotcha: { deep: true }
When watching nested objects, Vue only watches the object reference. If a property inside the object changes, the watcher won't trigger unless you set { deep: true }.
[!WARNING]
Using { deep: true } requires Vue to traverse the entire nested object tree recursively to attach reactivity triggers. For large, deeply nested objects, this traversal is incredibly expensive and can block main-thread execution. Prefer watching specific nested keys instead:
watch(() => user.profile.avatar, (newAvatar) => )
Finished practicing this challenge?
Mark it as completed to track your progress, or bookmark it to review later.