ref() vs. reactive(): Vue's Two Flavors of Reactivity
ref() is a box for any value (primitive or object) that you must access with .value. reactive() is a proxy for objects only, which you access directly. Use ref() for single values, reactive() for grouping data. The footgun: reactive() fails on primitives.
WHY IT EXISTS Vue needs a way to know when your data changes so it can update the user interface. In the Composition API, standard JavaScript variables aren't tracked. Vue provides ref() and reactive() to create explicitly 'reactive' data sources that Vue can watch for changes.
THE MENTAL MODEL Think of ref() as a labeled box for a single item. It can hold a number, a string, or even an object. To see or change what's inside, you must open the box using .value. reactive() is different; it's like enchanting an entire object. It takes your object and returns a magical version (a Proxy) where any change to its properties is automatically tracked. You don't use .value; you just modify properties as usual.
HOW IT WORKS ref(initialValue) wraps the value in an object: { value: initialValue }. Vue's reactivity system is hooked into the .value property's getter and setter. reactive(object) uses a JavaScript Proxy to wrap your object. When you get or set a property on this proxy, Vue intercepts the operation to track dependencies and trigger updates. This proxy-based mechanism is why reactive() only works on objects, arrays, and other non-primitive types.
WHEN TO USE IT A general rule is to use ref() for everything, especially for primitive values (strings, numbers, booleans). It's also useful when you might need to reassign the entire value, like myRef.value = anotherObject. Use reactive() as a deliberate choice for grouping a large number of properties into a single object that you intend to mutate but not replace, such as the state for a complex form.
WHEN NOT TO USE IT Never use reactive() with primitive values; it will not work. The biggest footgun with reactive() is losing reactivity when destructuring. If you pull properties out of a reactive object into local variables, like const { email } = formState;, that email variable is just a plain string and is no longer connected to the reactive state. This is a primary reason many developers prefer ref() for its consistency.
ONE CANONICAL EXAMPLE To create a reactive counter, you'd use const count = ref(0). To increment it, you'd write count.value++. For a user profile object, you could use const user = reactive({ name: 'Alex', age: 30 }). To update the age, you'd write user.age++. Notice the difference: ref() always requires .value to access the underlying value, while reactive() does not.
Read the original → vuejs.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.