Skip to main content

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.

javascript
data() { return { user: { name: 'Tim' } } } this.user.age = 30 // not reactive! Vue.set(this.user, 'age', 30) // needs to be done manually

In Vue 3

Proxy intercepts all get, set, delete operations, so Vue automatically tracks new fields:

javascript
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:

    javascript
    this.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.

javascript
const arr = reactive(['a', 'b']) arr[1] = 'x' // reactive arr.push('c') // reactive arr.length = 0 // reactive

Problem 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.
javascript
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.

javascript
const state = reactive({ nested: { count: 0 } }) state.nested.count++ // reactive, even though the object is nested

Problem 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:

javascript
const map = reactive(new Map()) map.set('key', 'value') // reactive map.delete('key') // reactive

Problem 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.

javascript
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().

javascript
// 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.js

Problem 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

ProblemVue 2Vue 3 (Proxy)
Adding/removing propertiesNoYes
Working with arraysPartialFull
Nested objectsNot automaticAutomatic
Map/Set supportNoYes
Creation performanceLowHigh
Tracking granularityCoarsePrecise
Use outside componentsNoYes
Debugging transparencyLimitedExcellent

In short

The new Vue 3 reactivity system built on Proxy solved the main problems of the old version, making reactivity universal, scalable, fast, and precise, while keeping Vue's declarative style simple.

Short Answer

Interview ready
Premium

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