Why ref Is Preferred Over reactive in Vue 3: Limitations of reactive and Best Practices
This article explains the fundamental differences between Vue 3's reactive and ref APIs, highlighting reactive's limitation to objects, the situations where it loses reactivity, and why using ref—along with techniques like Object.assign and toRefs—provides more reliable and flexible state management.
The Vue 3 reactive API can only wrap reference types (objects and arrays), while ref can wrap any value type, including primitives, objects, and arrays. Because of this, reactive often loses reactivity when the whole object is reassigned, when properties are destructured, or when the reactive object is passed to a function.
Key comparison:
reactive ref❌ Supports only objects/arrays
✅ Supports primitives + reference types
✅ Can be used directly in
<script>and
<template>❌ Requires
.valuein
<script>(template accesses value automatically)
❌ Reassigning a new object drops reactivity
✅ Reassigning a new object keeps reactivity
❌ Direct property access works
❌ Must use
.valueto read/write
❌ Passing to a function loses reactivity
✅ Passing to a function retains reactivity
❌ Destructuring loses reactivity (needs
toRefs)
❌ Same issue; use
toRefsafter
refif needed
Common pitfalls with reactive and solutions:
Do not replace the whole reactive object; assign properties individually. let state = reactive({ count: 0 }) // wrong – loses reactivity state = { count: 1 } // correct state.count = 1
Use Object.assign to merge new values without breaking the proxy. state = Object.assign(state, { count: 1 })
When you need to replace the whole object, prefer ref : let state = ref({ count: 0 }) state.value = { count: 1 } // works
For destructuring, use toRefs so each property remains a ref . const state = reactive({ count: 0 }) let { count } = toRefs(state) count.value++ // updates state.count
When passing reactive data to functions, pass the property itself or use ref to keep tracking. function fn(val) { console.log(val) } fn(state.count) // loses tracking // use ref instead let count = ref(state.count) fn(count.value)
Because ref requires the .value suffix, many developers rely on IDE plugins (e.g., Volar) to auto‑complete this boilerplate, making the code easier to write while still clearly indicating reactive variables.
In summary, ref offers a broader applicability, fewer pitfalls, and clearer intent, making it the recommended API for most Vue 3 state‑management scenarios.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.