Proxy and the new reactivity system
1. Problem: inability to track new properties
In Vue 2
Reactivity was created using Object.defineProperty().
It "wrapped" only the fields that existed at initialization time.
data() {
return { user: { name: 'Tim' } }
}
this.user.age = 30 // not reactive!
Vue.set(this.user, 'age', 30) // needs to be done manuallyIn Vue 3
Proxy intercepts all get, set, delete operations,
so Vue automatically tracks new fields:
const user = reactive({ name: 'Tim' })
user.age = 30 // reactive!
delete user.name // also reactive!Problem solved: properties can be added/removed dynamically, without Vue.set().
2. Problem: poor handling of arrays
In Vue 2
Arrays were not fully reactive:
-
Changes by index were not tracked:
javascriptthis.items[2] = 'new' // will not work -
Vue.set(this.items, 2, 'new')had to be used instead. -
Vue "patched" (
override) array methods (push,pop,splice), which was cumbersome and reduced performance.
In Vue 3
Proxy intercepts all array operations, including indices and length.
const arr = reactive(['a', 'b'])
arr[1] = 'x' // reactive
arr.push('c') // reactive
arr.length = 0 // reactiveProblem solved: arrays now work fully natively.
3. Problem: nested objects
In Vue 2
During initialization, Vue recursively walked through all the fields of an object to "wrap" them in getters/setters. This was:
- Slow with large data.
- Impossible for objects added later.
this.obj = { nested: { value: 1 } }
// obj.nested is not reactive until it goes through defineReactive()In Vue 3
Proxy creates reactivity lazily (on demand):
on the first access to a nested object, it is automatically wrapped in a Proxy.
const state = reactive({ nested: { count: 0 } })
state.nested.count++ // reactive, even though the object is nestedProblem solved: instant reactivity at any nesting level.
4. Problem: inability to track collections (Map, Set, WeakMap)
In Vue 2
These data structures could not be reactive at all,
since Object.defineProperty() cannot intercept their methods (set, get, add, delete).
In Vue 3
Proxy intercepts collection methods through special traps.
Reactive Map and Set can now be used freely:
const map = reactive(new Map())
map.set('key', 'value') // reactive
map.delete('key') // reactiveProblem solved: modern data structures can be used with full reactivity.
5. Problem: redundant updates and performance leaks
In Vue 2
The Dep dependency system worked at the property level,
and sometimes subscribers fired an extra time even if the value had not changed.
this.value = 10
this.value = 10 // still triggers an update!In Vue 3
The new track() / trigger() system became granular and precise:
- Vue compares the old and new value.
- It tracks dependencies by a specific key.
- It minimizes repeated updates.
Problem solved: fewer unnecessary re-renders, higher performance.
6. Problem: inability to use reactivity outside a component
In Vue 2
Reactivity was tightly coupled to the component lifecycle. You could not create "reactive state" outside a component without an internal API.
In Vue 3
Reactivity was moved into a separate @vue/reactivity package,
and is available via ref(), reactive(), computed(), watchEffect().
// can be used even without a Vue component
import { reactive, watchEffect } from 'vue'
const state = reactive({ count: 0 })
watchEffect(() => {
console.log(state.count)
})
state.count++ // reactive even in Node.jsProblem solved: reactivity became universal, independent of components.
7. Problem: initialization performance
In Vue 2
To make an object reactive, Vue walked through all of its properties
and called Object.defineProperty() on each one.
If data was large, the component mounted slowly.
In Vue 3
Proxy does not require walking through properties,
Vue creates a single proxy object and handles access "on demand".
Problem solved: component initialization became many times faster.
8. Problem: opacity of debugging and predictability
In Vue 2
In some cases reactivity worked "magically":
it was impossible to tell exactly where something was triggered, especially with Vue.set().
In Vue 3
The new system is transparent:
- There are separate low-level APIs (
effect,track,trigger). - Dependencies can easily be logged and debugged.
- DevTools shows a detailed map of reactive connections.
Problem solved: better understanding and control over reactivity.
Summary: which problems Proxy solves
| Problem | Vue 2 | Vue 3 (Proxy) |
|---|---|---|
| Adding/removing properties | No | Yes |
| Working with arrays | Partial | Full |
| Nested objects | Not automatic | Automatic |
| Map/Set support | No | Yes |
| Creation performance | Low | High |
| Tracking granularity | Coarse | Precise |
| Use outside components | No | Yes |
| Debugging transparency | Limited | Excellent |
In short
The new Vue 3 reactivity system built on
Proxysolved the main problems of the old version, making reactivity universal, scalable, fast, and precise, while keeping Vue's declarative style simple.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.