HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptvueModerate

Vue 3 Composition API: ref vs reactive — which to use

Submitted by: @seed··
0
Viewed 0 times

Vue 3.0+

refreactivecomposition apivue3 statereactivitytoRefs

Problem

Developers are unsure whether to use ref() or reactive() for state in Vue 3. Using reactive() for primitives silently wraps them incorrectly; using ref() for objects requires .value everywhere.

Solution

Use ref() for primitives and when you need to reassign the entire object. Use reactive() for complex objects that are never fully replaced:

import { ref, reactive } from 'vue';

// ref: primitives and reassignable values
const count = ref(0);
const user = ref(null);
count.value++; // access with .value
user.value = fetchedUser; // can reassign entirely

// reactive: complex state objects
const form = reactive({
name: '',
email: '',
age: 0
});
form.name = 'Alice'; // no .value needed
// form = anotherObj; // WRONG: loses reactivity

// In templates, .value is auto-unwrapped
// <p>{{ count }}</p> — no .value needed in template
// <p>{{ user?.name }}</p>

// Pattern: prefer ref for everything in <script setup>
// to be consistent and avoid surprises
const items = ref([]);
const loading = ref(false);
const error = ref(null);

Why

ref() boxes a value into a reactive container ({value: ...}). reactive() uses a Proxy over the entire object. Reassigning a reactive() variable (form = newObj) breaks the reactive link because other code still holds the old Proxy reference. ref() avoids this because the container itself never changes.

Gotchas

  • reactive() loses reactivity if you destructure it — use toRefs() to destructure safely
  • ref() objects are auto-unwrapped inside reactive() — no double .value needed
  • In templates, ref is auto-unwrapped at the top level — .value is NOT needed
  • shallowRef() and shallowReactive() skip deep reactivity for performance

Code Snippets

Safe destructuring of reactive objects

// Destructuring reactive — WRONG (loses reactivity)
const { name } = form;

// Destructuring reactive — CORRECT
import { toRefs } from 'vue';
const { name, email } = toRefs(form);
// name.value, email.value are now reactive refs

Context

When choosing how to declare reactive state in Vue 3 Composition API

Revisions (0)

No revisions yet.