Vue Watchers Pattern
React to data changes with watch and watchEffect for side effects and async operations
When to Use
- You need to perform side effects (API calls, localStorage writes, analytics) when reactive data changes
- Implementing debounced search, auto-save, or data synchronization
- Watching route params or store state for navigation-driven updates
Instructions
- Use
watch(source, callback) when you need the old and new values.
- Use
watchEffect(callback) when you want automatic dependency tracking.
- Pass
{ deep: true } to watch nested object mutations.
- Always clean up side effects in the
onCleanup callback to prevent leaks.
import { ref, watch, watchEffect } from 'vue';
const query = ref('');
// Explicit source — gives old and new
watch(query, (newVal, oldVal) => {
console.log(`Query changed: ${oldVal} → ${newVal}`);
});
// Auto-tracked dependencies
watchEffect((onCleanup) => {
const controller = new AbortController();
fetch(`/api/search?q=${query.value}`, { signal: controller.signal });
onCleanup(() => controller.abort());
});
- Use
{ immediate: true } with watch to run the callback immediately on setup.
- Watch multiple sources:
watch([ref1, ref2], ([new1, new2], [old1, old2]) => { ... }).
Details
Vue provides two watcher APIs. watch() is explicit — you declare what to watch and get old/new values. watchEffect() is implicit — it automatically tracks any reactive dependency accessed during execution. Both return a stop function to cancel the watcher.
Trade-offs:
watchEffect can trigger unexpectedly if it accesses reactive data you did not intend to track
- Deep watching large objects is expensive — Vue must traverse the entire object tree
- Watchers run asynchronously by default (after DOM updates) — use
{ flush: 'sync' } if you need synchronous execution (rare)
When NOT to use:
- For derived/computed values — use
computed() instead, which caches the result
- For template-reactive data — just use
ref/reactive directly; Vue re-renders automatically
- When a simple event handler would suffice — do not use a watcher to react to user clicks
Source
https://patterns.dev/vue/watchers-pattern
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.
1---2name: vue-watchers-pattern-23description: Vue Watchers Pattern4---5# Vue Watchers Pattern67> React to data changes with watch and watchEffect for side effects and async operations89## When to Use1011- You need to perform side effects (API calls, localStorage writes, analytics) when reactive data changes12- Implementing debounced search, auto-save, or data synchronization13- Watching route params or store state for navigation-driven updates1415## Instructions16171. Use `watch(source, callback)` when you need the old and new values.182. Use `watchEffect(callback)` when you want automatic dependency tracking.193. Pass `{ deep: true }` to watch nested object mutations.204. Always clean up side effects in the `onCleanup` callback to prevent leaks.2122```typescript23import { ref, watch, watchEffect } from 'vue';2425const query = ref('');2627// Explicit source — gives old and new28watch(query, (newVal, oldVal) => {29 console.log(`Query changed: ${oldVal} → ${newVal}`);30});3132// Auto-tracked dependencies33watchEffect((onCleanup) => {34 const controller = new AbortController();35 fetch(`/api/search?q=${query.value}`, { signal: controller.signal });36 onCleanup(() => controller.abort());37});38```39405. Use `{ immediate: true }` with `watch` to run the callback immediately on setup.416. Watch multiple sources: `watch([ref1, ref2], ([new1, new2], [old1, old2]) => { ... })`.4243## Details4445Vue provides two watcher APIs. `watch()` is explicit — you declare what to watch and get old/new values. `watchEffect()` is implicit — it automatically tracks any reactive dependency accessed during execution. Both return a stop function to cancel the watcher.4647**Trade-offs:**4849- `watchEffect` can trigger unexpectedly if it accesses reactive data you did not intend to track50- Deep watching large objects is expensive — Vue must traverse the entire object tree51- Watchers run asynchronously by default (after DOM updates) — use `{ flush: 'sync' }` if you need synchronous execution (rare)5253**When NOT to use:**5455- For derived/computed values — use `computed()` instead, which caches the result56- For template-reactive data — just use `ref`/`reactive` directly; Vue re-renders automatically57- When a simple event handler would suffice — do not use a watcher to react to user clicks5859## Source6061https://patterns.dev/vue/watchers-pattern6263## Process64651. Read the instructions and examples in this document.662. Apply the patterns to your implementation, adapting to your specific context.673. Verify your implementation against the details and edge cases listed above.6869## Harness Integration7071- **Type:** knowledge — this skill is a reference document, not a procedural workflow.72- **No tools or state** — consumed as context by other skills and agents.7374## Success Criteria7576- The patterns described in this document are applied correctly in the implementation.77- Edge cases and anti-patterns listed in this document are avoided.