The Vue reactivity system is the core mechanism that automatically updates the DOM whenever data changes. Internally, it uses proxies (in Vue 3) to track dependencies and trigger re-renders when reactive data is modified.
What is the Vue reactivity system and how does it work internally?
Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.
Overview
The Vue reactivity system is what makes Vue applications dynamic and responsive. It allows your UI to automatically update when underlying data changes — without manually manipulating the DOM. In Vue 3, this system is powered by ES6 Proxies, which intercept and track operations on reactive objects.
How Vue Reactivity Works
Vue’s reactivity is built around three key concepts:
- Reactive Data: Data that Vue tracks for changes.
- Dependency Tracking: Vue keeps track of which components or functions depend on which pieces of data.
- Reactivity Triggers: When data changes, Vue automatically re-runs or re-renders the parts of the app that depend on that data.
1. Creating Reactive Data
In Vue 3, the reactive() and ref() APIs from the Composition API are used to create reactive data sources.
import { reactive, ref } from 'vue';
const state = reactive({ count: 0 });
const message = ref('Hello Vue!');
Here, both state and message become reactive — Vue wraps them in a proxy that intercepts reads and writes to track changes.
2. Tracking Dependencies
When a component renders and accesses reactive properties, Vue records which reactive values were used. These dependencies are stored in an internal data structure called a Dependency Map (a WeakMap under the hood).
// Pseudo-code of dependency tracking
function track(target, key) {
const effect = activeEffect; // current rendering effect
if (effect) {
let depsMap = targetMap.get(target);
if (!depsMap) targetMap.set(target, (depsMap = new Map()));
let dep = depsMap.get(key);
if (!dep) depsMap.set(key, (dep = new Set()));
dep.add(effect);
}
}
Every time a reactive property is accessed during rendering, Vue calls track() to register the current watcher or computed effect as a dependency.
3. Triggering Updates
When a reactive value changes, Vue triggers an update by looking up all the effects (like component re-renders or computed properties) that depend on that property, then re-executes them.
// Pseudo-code of triggering updates
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(key);
if (dep) {
dep.forEach(effect => effect());
}
}
This ensures that only the parts of the app that depend on the modified property are re-run, leading to efficient updates instead of full-page re-renders.
4. Vue 2 vs Vue 3 Reactivity
In Vue 2, reactivity was achieved with Object.defineProperty() — Vue defined getters and setters for each property. However, it couldn’t detect new properties or array index changes easily.
In Vue 3, the system uses Proxies, which can intercept all property operations (get, set, delete, etc.), enabling full reactivity without these limitations.
Feature | Vue 2 (Object.defineProperty) | Vue 3 (Proxy) |
|---|---|---|
Detect new properties | ❌ Not supported | ✅ Supported |
Detect array index changes | ❌ Limited | ✅ Fully supported |
Performance | Moderate | Faster and more efficient |
Memory usage | Higher due to watchers | Lower, centralized dependency tracking |
5. Computed Properties and Watchers
Computed properties in Vue use this same reactivity mechanism but cache results until their dependencies change. Watchers use reactive tracking to run custom logic when specific data updates.
import { reactive, computed, watch } from 'vue';
const state = reactive({ count: 0 });
const doubled = computed(() => state.count * 2);
watch(() => state.count, (newVal, oldVal) => {
console.log('Count changed:', oldVal, '→', newVal);
});
Here, both computed() and watch() rely on Vue’s dependency tracking to know when state.count changes.
6. Virtual DOM Integration
When data changes, Vue marks affected components for re-rendering. During the next render cycle, Vue’s virtual DOM efficiently diffs the new and old virtual trees and updates only the changed elements in the real DOM.
Why It’s Efficient
Vue’s reactivity is fine-grained — it tracks dependencies at the property level. This means only the parts of your UI that depend on changed data are updated. Combined with virtual DOM diffing, this provides excellent runtime performance even for large applications.
Think of the Vue reactivity system as an intelligent observer — it watches over your data, remembers what depends on it, and instantly updates only what’s necessary when something changes.
Summary
- Vue’s reactivity system tracks dependencies using Proxies and WeakMaps.
- Reactive objects trigger updates only for the affected properties.
- Vue 3’s Proxy-based reactivity is faster, more complete, and easier to maintain than Vue 2’s system.
- Computed properties and watchers build upon the same reactive foundation.