DEV Community

Cover image for What ref() and reactive() Are Actually For
Yasin Demir
Yasin Demir

Posted on • Originally published at ysndmr.com

What ref() and reactive() Are Actually For

Vue 3 gives you two ways to make something reactive: ref() and reactive(). The docs explain the difference clearly enough. What they don't tell you is which one to reach for by default.

The short answer: ref(), almost always. reactive() for specific situations where you know what you're trading away.

Here's the problem with reactive(). It loses reactivity when you destructure it or reassign the root object, which catches people off guard more than it should.

const state = reactive({ count: 0, name: '' });

state.count++;       // works, Vue tracks this
const { count } = state;
count++;             // doesn't work, Vue has no idea
Enter fullscreen mode Exit fullscreen mode

ref() sidesteps this because the reactive pointer lives on the .value property. You can pass a ref anywhere, destructure the container, and the ref itself stays tracked.

The case where reactive() actually earns its place: a form object where all the values are always read and written together, passed as-is to a composable, and you're never going to replace the whole reference. Some people find dropping the .value noise worth that constraint. I get it. But in composables especially, ref() is much easier to work with because you can return individual refs that stay reactive when the caller destructures them.

export function useCounter() {
  const count = ref(0);
  const increment = () => count.value++;
  return { count, increment };
}

const { count, increment } = useCounter(); // both still reactive
Enter fullscreen mode Exit fullscreen mode

You can't do that cleanly with reactive() — destructuring breaks the connection.

For most of the time I was figuring out the ref/reactive split, I was making it more complicated than it needed to be. Default to ref(). Reach for reactive() when you have a specific reason. That's the whole decision.

Top comments (2)

Collapse
 
frank_signorini profile image
Frank

I've been using ref() for primitive types, but how do you decide when to use reactive() instead? I'd love to hear more about your approach.

Collapse
 
ysndmr profile image
Yasin Demir • Edited

Good question, but it's not really primitive vs object; ref() handles objects fine too, Vue just wraps them in reactive() under the hood anyway. Same deep reactivity either way.

Real question is whether you ever destructure or reassign the thing. If yes, use ref() — destructuring breaks reactive(), not ref(). I only reach for reactive() for stuff like a form object where everything moves together and you're never swapping out the whole thing.