Choosing Between ref and reactive
What is the difference between `ref()` and `reactive()` in Vue 3, and when would you choose one over the other?
what they're testing: The interviewer is checking whether you understand how Vue tracks state and can avoid common reactivity-loss bugs.
ref() wraps any value in an object with a reactive .value property. reactive() returns a reactive Proxy for an object. In script code, you read or replace a ref through .value, while a reactive object's properties are accessed normally. Templates unwrap top-level refs, so {{ count }} works without .value.
The choice is not simply "primitives versus objects." reactive() accepts objects, including arrays and collections, but not primitives. It works well for a stable object whose properties are mutated, such as form.email = value. ref() accepts both primitives and objects, and it supports replacing the whole value with items.value = newItems. A normal ref also makes an object value deeply reactive.
The main trap with reactive() is replacement. Reassigning the variable loses the reactivity connection to the first proxy. Destructuring a primitive property also produces a plain value that is no longer connected to the proxy. A ref can be passed to a function as a container while retaining its reactive connection through .value. Vue recommends ref() as the primary API for reactive state; reactive() remains convenient for a cohesive object that will be mutated in place.
Where people slip
the tempting wrong answer, and what's actually true
Use `ref()` for primitives and `reactive()` for objects.
`ref()` also accepts objects and makes them deeply reactive, so replacement and API ergonomics matter more than that simple split.
A variable holding a `reactive()` object can be reassigned without affecting reactivity.
Replacing that variable disconnects it from the proxy Vue was tracking, so mutate its properties or use a ref for replaceable state.
Object refs are shallow, while `reactive()` tracks nested changes.
A normal object ref is deeply reactive because Vue converts its non-primitive value through `reactive()`.
Refs always require `.value`, including in templates.
Top-level refs are automatically unwrapped in templates, although script code and some nested collection cases still require `.value`.
If they push further
What happens if you destructure a reactive object?
Destructuring a primitive property breaks its connection to the proxy; keep property access on the proxy or use `toRefs()` when reactive bindings must be destructured.
Are refs containing objects shallow or deep?
They are deep by default because object values are converted with `reactive()`; use `shallowRef()` when only replacement of `.value` should trigger updates.
When is `reactive()` still a good choice?
It reads naturally for a cohesive object whose identity stays stable and whose properties are mutated in place, such as local form state.
Sources
- Vue.js: Reactivity Fundamentals ↗vuejs.org
- Vue.js: Reactivity API: Core ↗vuejs.org
- Vue.js: Reactivity in Depth ↗vuejs.org
- Vue.js: Reactivity API: Utilities ↗vuejs.org
- Vue.js: Reactivity API: Advanced ↗vuejs.org
Now answer it yourself.
Reading a strong answer is easy. Producing one under pressure is the skill the interview tests. Gapmap grades your answer against the same bar an interviewer would.
beta
The interviewer part is in the works.
The diagnostic, personal maps, and AI mock interviews are being finished right now. The notes stay free either way. Leave an email and you'll get the first-cohort invite, plus a month of Pro when it opens.