Vue · Reactivity

Vue 3 Reactivity Deep Dive

Vue 3's reactivity feels like magic until it silently stops working. Understanding the Proxy-based system is what turns 'why didn't my UI update' into an obvious fix.

John Kihiu12 min read

Vue 3's reactivity is what makes the UI update automatically when data changes, and most of the time it just works. The trouble comes when it silently stops — you change a value and nothing re-renders — and without understanding how the system works, that is baffling. A little knowledge of the Proxy-based mechanism turns those mysteries into predictable, avoidable mistakes.

Proxy-based tracking

Vue 3 rebuilt reactivity on JavaScript Proxies. When you make an object reactive with reactive(), Vue wraps it in a Proxy that intercepts property reads and writes. On read, it tracks which effect (a render, a computed, a watcher) depends on that property; on write, it triggers those effects to re-run. This is why reactivity feels automatic — the Proxy is watching every access. It is also why the gotchas exist: they are all cases where you accidentally step outside the Proxy's view.

Why ref needs .value

JavaScript primitives (numbers, strings) cannot be proxied directly, so Vue wraps them in a ref object whose .value property can be tracked. That is the whole reason for the .value you write in script code. In templates Vue unwraps refs automatically, which is why you omit .value there. reactive() is for objects and needs no .value; ref() is for anything and always does in script.

Where reactivity breaks

JavaScript · keep reactivity through destructuring
import { reactive, toRefs } from 'vue'

const state = reactive({ x: 0, y: 0 })
const { x, y } = toRefs(state)   // x and y stay reactive refs
// const { x } = state           // x is a plain number — NOT reactive
Lost reactivity is almost always a broken connection

When the UI stops updating, you have almost certainly severed the Proxy link — by destructuring, reassigning, or passing a plain value where a reactive one was expected. Trace where the value left the reactive system, and use toRefs or keep the reference intact. Reactivity does not fail randomly; it fails where you stepped outside the Proxy.

Vue 3 reactivity is a Proxy system that tracks reads and triggers on writes, with ref wrapping primitives so their .value can be watched. Every classic gotcha — lost updates after destructuring or reassignment — is a case of breaking that Proxy connection. Understand the mechanism and reactivity stops being magic that mysteriously fails and becomes a system whose rules you can follow.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.