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:
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:
- Creating the Proxy
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
}
})- 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:
javascripttargetMap = WeakMap { target (object) -> Map { key (field) -> Set(effect) } }
- 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:
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()andVue.delete()
That is why Vue 3 switched to Proxy, which solves all these problems.
Summary
| Vue version | Reactivity mechanism | What it intercepts | Limitations |
|---|---|---|---|
| Vue 2 | Object.defineProperty() | Only existing properties | Does not see new keys, requires Vue.set() |
| Vue 3 | Proxy | Any read/write operations, including new properties | No limitations, faster and cleaner |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.