Skip to main content

How does Vue track data changes?

How Vue tracks data changes

Vue implements a reactivity system based on Proxy (in Vue 3) or Object.defineProperty() (in Vue 2). The core idea is intercepting access to object properties (reading and writing) to know:

  • when data is read -> register a dependency
  • when data changes -> notify the dependent effects (components, computed properties, watch, etc.)

The mechanism at the Proxy level (Vue 3)

When you create a reactive object via reactive() or ref(), Vue wraps it with a Proxy.

Example:

javascript
import { reactive, effect } from 'vue' const state = reactive({ count: 0 }) effect(() => { console.log(`Count: ${state.count}`) }) state.count++ // triggers the effect -> logs "Count: 1"

What happens step by step:

  1. Creating the Proxy
javascript
const proxy = new Proxy(target, { get(target, key, receiver) { track(target, key) // registers the dependency return Reflect.get(target, key, receiver) }, set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver) trigger(target, key) // notifies subscribers about the change return result } })
  1. The track() function
  • Called when the property is read (get).

  • Registers that the current computation (for example, a component render) depends on this property.

  • Vue stores dependencies in a WeakMap -> Map -> Set:

    javascript
    targetMap = WeakMap { target (object) -> Map { key (field) -> Set(effect) } }
  1. The trigger() function
  • Called when the property is written (set).
  • Finds all effects (for example, render functions) that depend on the changed key.
  • Calls them again -> the interface updates.

The mechanism in Vue 2 (Object.defineProperty)

The old version of Vue had no Proxy, so Vue redefined the getters and setters of every property manually:

javascript
Object.defineProperty(obj, 'count', { get() { Dep.depend() // subscribe the watchers return value }, set(newVal) { value = newVal Dep.notify() // notify all watchers } })

But this approach had limitations:

  • it could not track the addition of new properties (obj.newProp = ...)
  • it could not track the removal of properties
  • you had to use Vue.set() and Vue.delete()

That is why Vue 3 switched to Proxy, which solves all these problems.


Summary

Vue versionReactivity mechanismWhat it interceptsLimitations
Vue 2Object.defineProperty()Only existing propertiesDoes not see new keys, requires Vue.set()
Vue 3ProxyAny read/write operations, including new propertiesNo limitations, faster and cleaner

Short Answer

Interview ready
Premium

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