JAVASCRIPT
Mastering Reactive Objects vs. Primitives with `reactive` and `ref` in Vue 3
Understand the core differences and best practices for using `reactive` for objects/arrays and `ref` for primitives in Vue 3's reactivity system to avoid common pitfalls.
<script setup>
import { ref, reactive, watch } from 'vue';
// Using ref for primitives (numbers, strings, booleans)
const count = ref(0);
const message = ref('Hello');
// Using reactive for objects and arrays
const user = reactive({
id: 1,
name: 'Alice',
details: { age: 30, city: 'New York' }
});
const increment = () => {
count.value++; // Access with .value
};
const changeName = () => {
user.name = 'Bob'; // Direct access for reactive objects
user.details.age = 31;
};
// Destructuring reactive objects can lose reactivity if not careful
// INCORRECT: Will lose reactivity
// const { name, id } = user;
// name = 'Charlie'; // This won't update the original user object
// CORRECT: Using toRefs to retain reactivity when destructuring
import { toRefs } from 'vue';
const { name, id } = toRefs(user);
const changeNameViaToRefs = () => {
name.value = 'Charlie'; // Now it's reactive
};
// Watching a ref
watch(count, (newVal, oldVal) => {
console.log(`Count changed from ${oldVal} to ${newVal}`);
});
// Watching a reactive object (deep by default if a specific property is watched)
watch(() => user.name, (newVal, oldVal) => {
console.log(`User name changed from ${oldVal} to ${newVal}`);
});
// Watching deeply nested properties in a reactive object
watch(user.details, (newVal, oldVal) => {
console.log('User details changed deeply:', newVal, oldVal);
}, { deep: true });
</script>
<template>
<div>
<h3>Ref (Primitives)</h3>
<p>Count: {{ count }}</p>
<button @click="increment">Increment Count</button>
<p>Message: {{ message }}</p>
<h3>Reactive (Objects/Arrays)</h3>
<p>User Name: {{ user.name }} (via user.name)</p>
<p>User ID: {{ user.id }}</p>
<p>User Age: {{ user.details.age }}</p>
<button @click="changeName">Change User Name & Age</button>
<h3>Reactive with `toRefs` (for destructuring)</h3>
<p>User Name (via toRefs): {{ name }}</p>
<button @click="changeNameViaToRefs">Change User Name (via toRefs)</button>
<p>User ID (via toRefs): {{ id }}</p>
</div>
</template>
How it works: This snippet clarifies the usage of `ref()` for primitive values (like numbers, strings, booleans) and `reactive()` for objects and arrays in Vue 3's Composition API. It highlights that `ref` values are accessed/mutated via `.value`, while `reactive` objects are accessed directly. Crucially, it demonstrates how destructuring a `reactive` object directly can lead to loss of reactivity and introduces `toRefs()` as the correct way to destructure reactive properties while preserving their reactivity.