What Is Reactivity? The Magic Behind Vue.js Explained Clearly
Reactivity is the heart of Vue.js. It’s what makes the interface not just a pretty decoration, but a living system that responds to state changes without you having to chase the DOM like it’s 2012.
In this article, we’ll break the concept down without unnecessary mysticism: first with a simple analogy, then with what actually happens at a technical level, and finally with best practices that will save you bugs and performance headaches.
The analogy: the Excel effect
You don’t need a PhD in computer science to understand reactivity. You just need to have used Excel without breaking anything.
If in cell C1 you write the formula =A1 + B1, C1 updates automatically when A1 or B1 change. You don’t click “refresh,” you don’t rewrite the formula. It just happens.
That’s reactivity: an automatic relationship between data and results.
Real-world analogy: imagine a smart coffee maker. The moment it detects a cup is placed, the start button becomes enabled. Not because someone programs it each time, but because the system is watching the state.
The technical evolution: from Vue 2 to Vue 3
Vue didn’t always have the elegant reactivity system we know today. Understanding its evolution helps you write better code and avoid fighting the framework.
Vue 2: Object.defineProperty
In Vue 2, each reactive property was turned into a pair of getters and setters using Object.defineProperty.
- The limitation: Vue had to walk the entire object when initializing it. If you added a new property or changed an array index directly (
arr[0] = x), Vue wouldn’t notice. That’s why solutions likeVue.set()existed.
Vue 3: the power of Proxy
Vue 3 completely changed the approach by using JavaScript Proxies.
A Proxy wraps an object and can intercept almost any operation: reading, writing, deleting, or adding properties.
- The advantage: it doesn’t matter when or how the object changes. Vue can detect it. The result is deeper, more predictable reactivity with better performance.
The two pillars: ref() vs reactive()
If you use the Composition API, this question shows up before you finish your first coffee.
| Feature | ref() | reactive() |
|---|---|---|
| Data type | Primitives and objects | Only objects and collections |
| Access in JS | .value | Direct access |
In <template> | Auto-unwrapped | Direct access |
| Ideal use | Simple, isolated state | Complex or nested state |
A quick mental rule: if it’s one thing, use ref. If it’s a structure, use reactive.
The internal cycle: track and trigger
Vue’s reactivity engine works with a surprisingly elegant system:
- Track: when a function reads a reactive variable, Vue records that relationship.
- Trigger: when the value changes, Vue notifies all functions that depend on it.
- Update: the component re-renders. The Virtual DOM takes care of updating only what’s necessary.
You change data. Vue decides what to touch in the DOM. Separation of responsibilities at its finest.
Performance tips (2026 level)
If your application starts to grow, these decisions matter more than they seem.
shallowRefandshallowReactive: useful when you’re working with large objects that don’t need deep reactivity.- Be careful when destructuring: doing this breaks reactivity:
const { name } = reactiveState; // wrongThe correct way is:
import { reactive, toRefs } from 'vue';
const state = reactive({ name: 'Vue' });
const { name } = toRefs(state);Practical example: the most honest counter in the world
<script setup>
import { ref } from 'vue';
const coffeeCups = ref(0);
const increment = () => {
coffeeCups.value++;
};
</script>
<template>
<button @click="increment">
Cups consumed: {{ coffeeCups }}
</button>
</template><script>
import { ref } from 'vue';
export default {
setup() {
const coffeeCups = ref(0);
const increment = () => {
coffeeCups.value++;
};
return { coffeeCups, increment };
},
};
</script>
<template>
<button @click="increment">
Cups consumed: {{ coffeeCups }}
</button>
</template>Each click updates the state. Vue detects the change, re-renders what’s necessary, and you never touch the DOM. That’s reactivity understood properly: less imperative code, fewer mental errors, and an interface that does exactly what it should.



