Skip to content

watch and watchEffect

computed derives values from state. watch and watchEffect run side effects in response to state changes — logging, fetching data, updating localStorage, synchronizing with external systems.

watch observes a specific reactive source and runs a callback when it changes:

import { ref, watch } from 'vue'
const focusId = ref<string | null>(null)
watch(focusId, (newId, oldId) => {
console.log(`Focus changed from ${oldId} to ${newId}`)
})

The callback receives the new value and the previous value. This is useful when you need to know what changed.

watch(count, (newVal) => {
document.title = `Count: ${newVal}`
})
watch(currentSpouse, (spouse) => {
if (!spouse) console.log('No spouse currently')
})

To watch a property of a reactive object or a derived expression:

watch(
() => person.value?.name,
(newName) => {
console.log('Name changed to', newName)
}
)

By default, watch only runs when the value changes. Pass { immediate: true } to also run it once on setup:

watch(focusId, loadPersonData, { immediate: true })

watchEffect runs a callback immediately and re-runs it whenever any reactive value it reads changes. No explicit source — Vue tracks dependencies automatically:

import { watchEffect } from 'vue'
watchEffect(() => {
// runs immediately, then again whenever focusId or people changes
console.log('Current focus:', people.value.find(p => p.id === focusId.value))
})

Use watchEffect when you want to run a side effect that uses multiple reactive values and you don’t need the previous value.

Both watch and watchEffect return a stop function:

const stop = watchEffect(() => {
console.log(count.value)
})
// Later — stop the watcher
stop()

In components, watchers created in <script setup> are automatically stopped when the component unmounts. Manual stopping is only needed for watchers created outside setup.

PurposeWhen it runs
computedDerive a valueWhen dependencies change, lazily
watchSide effect on specific sourceWhen source changes
watchEffectSide effect on any dependencyImmediately, then on any dependency change
  1. Add a watch to a component that logs the new value of a ref<string> searchQuery whenever it changes.
  2. Add a watchEffect that updates document.title to include the current searchQuery.
  3. Add a { immediate: true } option to the watch and confirm it runs on setup.
  4. Compare: what does the watch provide that watchEffect doesn’t?
  • watch(source, callback) runs a side effect when a specific reactive source changes; provides new and old value.
  • watchEffect(callback) runs immediately and re-runs whenever any reactive value it reads changes.
  • Use watch when you need the previous value or want explicit source control.
  • Use watchEffect for fire-and-forget side effects that should run whenever their dependencies change.
  • Both are automatically cleaned up when the component unmounts.