Skip to main content

ref() vs reactive(): Vue Reactivity Deep Dive

Purpose

This guide clears up common misunderstandings around Vue's ref() and reactive() and helps you choose the right tool for your situation.


The Core Difference

  • ref() wraps any value (primitive or object) in a reactive container.
  • reactive() turns an object or array into a deeply reactive proxy.

ref()

const count = ref(0); // count.value === 0
const state = ref({ x: 1 }); // state.value.x === 1

reactive()

const state = reactive({ x: 1 });
console.log(state.x); // 1

When using ref(), always access the value with .value. With reactive(), you access fields directly.


Why It’s Confusing

  • ref() is also used to reference DOM elements in the template.
  • ref(store.something) doesn't "track" store.something — it just copies the value once.
  • You get awkward .value.prop or .value[index] syntax when wrapping complex types with ref().

Practical Guidelines

Use ref():

  • For primitive values (number, string, boolean)
  • For tracking a DOM element or component (ref(null) + ref="el" in template)
  • When you need a single reactive wrapper for any value (deep or shallow)

Use reactive():

  • When dealing with objects or arrays
  • When you want cleaner syntax (state.prop instead of state.value.prop)

Use computed():

  • When you want to derive a value reactively
  • When ref() would give you a stale snapshot

Gotchas

CaseDon't Do ThisDo This Instead
Want to track store valueref(store.count)computed(() => store.count)
Want reactive objectref({ a: 1 })reactive({ a: 1 })
Watch a fieldwatch(refObj.a, ...)watch(() => refObj.a, ...)

Analogy

  • ref() is a box that holds a value. You must open the box with .value.
  • reactive() is a live object where all properties are already reactive.
  • computed() is a window that always shows the current value.

Summary Table

Featureref()reactive()computed()
Syntax.value requireddirect accessread-only
Deep reactivityYes (but annoying)YesN/A
Best forPrimitives, DOM refsObjects, arraysDerived values

Final Tip

If you’re ever unsure which one to use:

  • Is it a primitive? → ref()
  • Is it an object or array? → reactive()
  • Do you need a live-updating value based on another? → computed()