Under The Hood
frontend vue Vue 3.x

watch() Lazy Source vs watchEffect() Flush Timing (pre, post, sync)

Last updated
Prerequisites:
Vue 3 Composition API
Vue ref() and reactive()
  • vue
  • watch
  • watchEffect
  • flush
  • reactivity
  • lifecycle

Read at your depth

The practical view

`watch(source, callback)` is lazy by default: it tracks explicit dependencies, provides `(newValue, oldValue)`, and only runs when the source changes. `watchEffect(callback)` runs immediately on initialization, automatically tracks any reactive dependencies read inside its body, but does not provide the previous value. The `flush` option (`'pre'`, `'post'`, `'sync'`) controls when the watcher callback executes relative to DOM updates.

The same idea in other frameworks

react equivalent
`useEffect` with dependency array (similar to post-flush watcher).

Legacy vs modern

Explicit watch() vs Automatic watchEffect() with Post-DOM Flush

`watch` requires explicit sources and previous values; `watchEffect` auto-tracks and can wait for DOM updates with `flush: 'post'`.

before → after
Accidental Pre-Flush DOM Read
watchEffect(() => { readDom(el.value); }); // ❌ Reads stale DOM before render
watchPostEffect for Fresh DOM Access
watchPostEffect(() => { readDom(buttonRef.value); }); // ✅ NEW: Guaranteed updated DOM

Interview gotchas

Context

Interviewers test your knowledge of Vue's render queue and DOM synchronization lifecycle.

The mechanical answer

- **`flush: 'pre'` (Default)**: Watcher callback runs before the component's DOM patch phase. Multiple state updates are batched into a single pre-render run. - **`flush: 'post'` (`watchPostEffect`)**: Watcher callback runs *after* the component's DOM patch phase. Use this whenever reading template refs or measuring DOM dimensions. - **`flush: 'sync'` (`watchSyncEffect`)**: Watcher runs immediately and synchronously the instant the ref/reactive property mutates, bypassing batching (use with caution as it can cause performance bottlenecks).

Trap

Accessing template refs inside a default `watchEffect` on initial run will yield `null` because the component has not mounted yet.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.