Skip to main content

What does watch() do?

1. What watch() does

watch() watches for changes in reactive values (created via ref, reactive, computed, etc.) and runs the given function only when those values actually change.

Syntax:

javascript
watch(source, callback, options?)
  • source - what we watch (ref, reactive, a function, or an array).
  • callback(newValue, oldValue) - called on change.
  • options - additional settings (immediate, deep, flush, etc).

2. The simplest example

javascript
import { ref, watch } from 'vue' const count = ref(0) watch(count, (newVal, oldVal) => { console.log(`count changed: ${oldVal}${newVal}`) }) count.value++ // triggers the callback

Here watch() "subscribes" to changes in count.value. When the value changes, the callback is called.


3. How it works internally

Under the hood, watch() creates an effect, just like computed, but with "only on change" behavior.

  1. Vue remembers which reactive data were used in the source function (source).
  2. When that data changes, Vue calls the callback.
  3. Vue compares the old and new value (a shallow comparison).
  4. If the value changed, your logic runs.

4. Example with a reactive object

javascript
import { reactive, watch } from 'vue' const user = reactive({ name: 'Tim', age: 25 }) // Watch the whole object watch(user, (newUser, oldUser) => { console.log('user changed:', newUser) })

But note:

When watching a reactive object, changes inside the object do not trigger the callback by default, unless you specify { deep: true }.

Correct:

javascript
watch(user, (newVal, oldVal) => { console.log('user changed deeply:', newVal) }, { deep: true })

5. Watching a specific property

Instead of the whole object, you can pass a function, a "selector".

javascript
watch( () => user.name, // watch only name (newName, oldName) => { console.log(`Name changed: ${oldName}${newName}`) } )

This is the preferred way - it is performant and targeted.


6. watch() options

OptionDescriptionExample
immediate: trueRun the callback immediately on initialization (with the current value)watch(count, cb, { immediate: true })
deep: trueWatch all nested changes in an object/arraywatch(user, cb, { deep: true })
flushDetermines when the watcher runs relative to the render.watch(value, cb, { flush: 'post' })
onCleanup(fn)Lets you clean up a side effect before the next callsee below

7. Cleaning up side effects

Often, watch() needs to clean up timers, subscriptions, and so on.

Vue passes an onCleanup function into the callback so you can clean up the previous effect:

javascript
watch(searchQuery, (newQuery, oldQuery, onCleanup) => { const controller = new AbortController() fetch(`/api?q=${newQuery}`, { signal: controller.signal }) // cancel the previous request if the value changed again onCleanup(() => controller.abort()) })

8. Watching several sources

You can watch several values at once by passing an array:

javascript
const first = ref('Tim') const last = ref('Cook') watch([first, last], ([newFirst, newLast], [oldFirst, oldLast]) => { console.log(`Name: ${oldFirst} ${oldLast}${newFirst} ${newLast}`) })

Vue tracks all the dependencies, and the callback is called if at least one of them changes.


9. Difference between watch() and watchEffect()

Criterionwatch()watchEffect()
What it tracksSpecific reactive values or functionsEverything used inside the effect
When it runsOnly when values changeImmediately on start and on every change
Has oldValueYesNo
Fine-grained controlYes (you can specify deep, immediate)No, everything is automatic
Typical caseReact to a state changeRun side effects on any change

Example:

javascript
// watch() watch(count, (newVal, oldVal) => console.log(newVal)) // watchEffect() watchEffect(() => { console.log(count.value) })

10. A practical example

For example, you want to react to a change in the search string, but not on every render:

javascript
const query = ref('') watch(query, async (newQuery) => { results.value = await fetch(`/api?q=${newQuery}`).then(r => r.json()) }, { immediate: true })

Here immediate: true gives the first request when the component mounts, and after that watch() only triggers when query changes.


11. Short and simple

watch() is a "reactive listener": it tracks specific data and calls a function when it changes.

You use it when you need to perform an action, not just update the UI.


An example to remember

What you wantWhat to use
I want the UI to update itself when the data changesreactive() / ref() / computed()
I want to run a side effect when the data changes (e.g. an API call, a log, a timer, local storage)watch()

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.