在 Vue 3 的 Composition API 中,reactive()
和 ref()
是两种用于创建响应式数据的主要方法。它们都能让数据变成响应式,但在使用场景和实现方式上有显著区别。以下是详细对比和介绍:
1. reactive()
基本概念
-
用途:将一个普通对象转换为响应式对象(深层响应式)。
-
返回值:返回一个
Proxy
代理对象,对象的嵌套属性也会自动变为响应式。 -
特点:只能用于对象类型(Object、Array、Map、Set 等),不能用于原始值(如
string
、number
、boolean
)。
使用方法
import { reactive } from 'vue';
const state = reactive({
count: 0,
user: {
name: 'Alice',
age: 25
}
});
// 修改数据会自动触发视图更新
state.count++;
state.user.name = 'Bob';
注意事项
const { count } = state; // 解构后 count 不再是响应式
若需解构,需配合 toRefs()
:
const { count } = toRefs(state); // count 是 ref 对象
2. ref()
基本概念
-
用途:创建一个响应式引用(可包装任意值,包括原始值)。
-
返回值:返回一个
RefImpl
对象,通过.value
访问内部值。 -
特点:
-
可以包装原始值(如
number
、string
)或对象。 -
在模板中自动解包(无需
.value
),但在 JS 中需通过.value
操作。
-
使用方法
import { ref } from 'vue';
const count = ref(0); // 包装原始值
const user = ref({ name: 'Alice', age: 25 }); // 包装对象
// 修改数据需通过 .value
count.value++;
user.value.name = 'Bob';
自动解包规则
-
模板中:直接使用,无需
.value
:<div>{{ count }}</div>
-
响应式对象内:嵌套在
reactive()
中时会自动解包:const state = reactive({ count }); console.log(state.count); // 无需 .value
3. 核心区别
特性 | reactive() | ref() |
---|---|---|
适用类型 | 对象类型(Object、Array 等) | 任意类型(包括原始值) |
访问/修改数据 | 直接访问属性(如 state.count ) | 需通过 .value (如 count.value ) |
模板中使用 | 直接使用 | 自动解包(无需 .value ) |
解构响应性 | 需要使用 toRefs() 保持响应性 | 解构后仍是 ref 对象 |
性能开销 | 较大(深层代理) | 较小(简单包装) |
4. 如何选择?
-
reactive()
:-
适合管理复杂的状态对象(如表单数据、全局状态)。
-
需要直接操作嵌套属性时更直观。
-
-
ref()
:-
适合包装原始值或需要灵活传递的响应式引用。
-
在组合式函数中返回状态时更常用(如
useFetch()
)。
-
5. 进阶技巧
互相转换
-
reactive()
包裹ref()
:const count = ref(0); const state = reactive({ count }); console.log(state.count); // 自动解包,无需 .value
-
toRef()
:将reactive
的属性转为ref
:const state = reactive({ count: 0 }); const countRef = toRef(state, 'count'); // 保持与源属性的响应式连接
性能优化
-
对大型不可变数据,可使用
shallowRef()
或shallowReactive()
避免深层响应式转换。
总结
-
reactive()
:面向对象,适合结构化状态管理。 -
ref()
:面向任意值,适合简单状态或组合式函数返回值。
理解两者的差异和适用场景,能更高效地组织 Vue 3 的响应式代码。