Vue Composition API: Refs and Reactive
The Composition API in Vue 3 introduces powerful ways to manage state and logic within components. Two core concepts for reactive state management are ref and reactive. Let's dive into each, their differences, and how to use them.
1. ref
Purpose:
refis used to create a reactive reference to a single value. It's ideal for primitive types (numbers, strings, booleans) and objects where you want to track changes to the value itself.How it works:
ref()takes an initial value as an argument.- It returns a reactive object with a
.valueproperty. You access and modify the actual value through this.valueproperty. - Vue automatically tracks dependencies on the
.valueproperty, triggering updates when it changes.
Example:
<template>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0); // Create a reactive ref with initial value 0
const increment = () => {
count.value++; // Increment the value through .value
};
return {
count,
increment
};
}
};
</script>
- Key Points:
- Always access and modify the value using
.value. Directly assigning tocount(without.value) will not make the component reactive. refis best for simple values and when you need to know when a specific value changes.- When passing a
refto a child component, Vue automatically unwraps the.valuefor you. You don't need to passcount.value.
- Always access and modify the value using
2. reactive
Purpose:
reactiveis used to create a reactive object. It's best suited for complex objects (like arrays or nested objects) where you want to track changes to the object's properties.How it works:
reactive()takes an object as an argument.- It returns a proxy of the original object. This proxy is reactive.
- Changes to the properties of the reactive object are automatically tracked, triggering updates.
- Unlike
ref, you access and modify properties directly on the reactive object, without using.value.
Example:
<template>
<p>Name: {{ person.name }}</p>
<p>Age: {{ person.age }}</p>
<button @click="updateAge">Update Age</button>
</template>
<script>
import { reactive } from 'vue';
export default {
setup() {
const person = reactive({
name: 'Alice',
age: 30
});
const updateAge = () => {
person.age++; // Update the age directly on the reactive object
};
return {
person,
updateAge
};
}
};
</script>
- Key Points:
- Access and modify properties directly (e.g.,
person.age). reactiveis ideal for complex objects with multiple properties.- When passing a
reactiveobject to a child component, you should pass the entire object. Vue does not automatically unwrap it like it does withref. reactivecannot be used with primitive types directly. You'd need to wrap them in an object first. (e.g.,reactive({ count: 0 }))
- Access and modify properties directly (e.g.,
3. ref vs. reactive: A Comparison
| Feature | ref |
reactive |
|---|---|---|
| Purpose | Single reactive value | Reactive object |
| Initial Value | Any type | Object |
| Access/Modify | .value property |
Direct property access |
| Best For | Primitives, simple values | Complex objects, nested data |
| Unwrapping | Automatic in child components | Manual (pass the entire object) |
4. Converting Between ref and reactive
Sometimes you might need to convert between these two types.
toRef: Creates areffor a specific property of areactiveobject. Thisrefis linked to the original property, so changes to theref.valuewill update the original object, and vice-versa.
import { reactive, toRef } from 'vue';
const state = reactive({ count: 0 });
const countRef = toRef(state, 'count');
countRef.value++; // Updates state.count as well
console.log(state.count); // Output: 1
toRefs: Converts all properties of areactiveobject into individualrefs. This is useful when you want to destructure a reactive object and pass individual reactive properties to child components.
import { reactive, toRefs } from 'vue';
const state = reactive({ count: 0, message: 'Hello' });
const { count, message } = toRefs(state);
count.value++; // Updates state.count
message.value = 'Goodbye'; // Updates state.message
5. Important Considerations
- Reactivity System: Both
refandreactiverely on Vue's reactivity system. Changes are tracked through proxies and dependency tracking. - Deep Reactivity:
reactiveprovides deep reactivity for nested objects. Changes within nested properties will trigger updates.refonly provides reactivity for the value it holds; nested properties within that value might not be reactive unless you also usereactiveorrefon them. - Performance: While both are efficient, be mindful of excessive use of
reactivewith very large objects, as it can impact performance. Consider usingreffor individual properties when appropriate.
By understanding ref and reactive, you can effectively manage state and build dynamic, responsive Vue components using the Composition API. Choose the appropriate tool based on the complexity of the data you're working with.