Run Code When Reactive State Changes
Watchers — watch() & watchEffect()
watch lets you react to changes in specific sources; watchEffect auto-tracks every reactive read inside its callback.
What you'll learn
- Watch a specific ref with watch()
- Auto-track with watchEffect
- Use immediate / deep / flush options
Watchers run side effects in response to reactive change — logging, fetching, syncing to localStorage. Vue offers two flavors: watch() (explicit sources) and watchEffect() (auto-tracked).
watch — Explicit Source
import { ref, watch } from 'vue'
const count = ref(0)
watch(count, (next, prev) => {
console.log(`went from ${prev} to ${next}`)
}) Multiple sources — pass an array:
watch([a, b], ([na, nb], [oa, ob]) => {
// runs when either changes
}) watchEffect — Auto-Tracked
watchEffect runs immediately, tracking any reactive value read inside it, and re-runs when those values change.
import { ref, watchEffect } from 'vue'
const count = ref(0)
watchEffect(() => {
console.log('count is', count.value)
})
// logs immediately, then again whenever count changes Options
watch(count, fn, {
immediate: true, // run once on setup
deep: true, // deep-watch objects
flush: 'post', // run after DOM update
}) Cleanup
The watch callback receives an onCleanup argument for canceling stale work — useful for fetch requests and timers.
watch(id, async (newId, _old, onCleanup) => {
const ctrl = new AbortController()
onCleanup(() => ctrl.abort())
const data = await fetch(`/api/${newId}`, { signal: ctrl.signal })
})