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.
Watching a ref
Section titled “Watching a ref”watch(count, (newVal) => { document.title = `Count: ${newVal}`})Watching a computed
Section titled “Watching a computed”watch(currentSpouse, (spouse) => { if (!spouse) console.log('No spouse currently')})Watching a getter function
Section titled “Watching a getter function”To watch a property of a reactive object or a derived expression:
watch( () => person.value?.name, (newName) => { console.log('Name changed to', newName) })immediate: true
Section titled “immediate: true”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
Section titled “watchEffect”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.
Stopping a watcher
Section titled “Stopping a watcher”Both watch and watchEffect return a stop function:
const stop = watchEffect(() => { console.log(count.value)})
// Later — stop the watcherstop()In components, watchers created in <script setup> are automatically stopped when the component unmounts. Manual stopping is only needed for watchers created outside setup.
watch vs watchEffect vs computed
Section titled “watch vs watchEffect vs computed”| Purpose | When it runs | |
|---|---|---|
computed | Derive a value | When dependencies change, lazily |
watch | Side effect on specific source | When source changes |
watchEffect | Side effect on any dependency | Immediately, then on any dependency change |
Exercise
Section titled “Exercise”- Add a
watchto a component that logs the new value of aref<string>searchQuerywhenever it changes. - Add a
watchEffectthat updatesdocument.titleto include the currentsearchQuery. - Add a
{ immediate: true }option to thewatchand confirm it runs on setup. - Compare: what does the
watchprovide thatwatchEffectdoesn’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
watchwhen you need the previous value or want explicit source control. - Use
watchEffectfor fire-and-forget side effects that should run whenever their dependencies change. - Both are automatically cleaned up when the component unmounts.