在 Vue 3 中,ref()
和 reactive()
是两种核心的响应式 API,用于创建和管理响应式数据。它们各有适用场景,理解它们的区别和用法对开发至关重要。以下是详细对比和示例:
1. ref()
的用法
1.1 基本概念
ref()
用于创建一个响应式引用,适用于基本数据类型(如number
、string
、boolean
)和复杂数据类型(如对象、数组)。- 返回值是一个带有
.value
属性的对象,即使传入的是复杂数据类型,也需通过.value
访问或修改值。
1.2 使用场景
- 需要直接操作基本数据类型(如计数器、布尔值)。
- 需要将整个对象或数组作为单一值管理(如动态替换整个对象)。
- 需要与 Vue 2 的
this.$data
行为兼容。
1.3 示例
import { ref } from 'vue';// 基本数据类型
const count = ref(0); // 创建一个响应式整数
console.log(count.value); // 读取值:0
count.value++; // 修改值:1// 复杂数据类型
const user = ref({ name: 'Alice', age: 20 }); // 创建一个响应式对象
console.log(user.value.name); // 读取对象属性
user.value.age = 21; // 修改对象属性// 数组
const list = ref([1, 2, 3]); // 创建一个响应式数组
list.value.push(4); // 修改数组
1.4 模板中使用
在模板中无需 .value
,Vue 会自动解包:
<template><div>{{ count }}</div> <!-- 自动显示 count.value --><div>{{ user.name }}</div> <!-- 自动显示 user.value.name -->
</template>
2. reactive()
的用法
2.1 基本概念
reactive()
用于创建一个响应式对象,适用于复杂数据类型(对象或数组)。- 返回值是一个代理对象(Proxy),直接访问或修改属性即可触发响应式更新,无需
.value
。
2.2 使用场景
- 管理嵌套复杂的对象或数组(如表单数据、配置对象)。
- 需要直接操作对象属性而不想用
.value
。
2.3 示例
import { reactive } from 'vue';// 对象
const user = reactive({ name: 'Bob', age: 25 }); // 创建响应式对象
console.log(user.name); // 直接访问属性
user.age = 26; // 直接修改属性// 数组
const list = reactive([1, 2, 3]); // 创建响应式数组
list.push(4); // 直接修改数组
2.4 模板中使用
直接绑定属性名:
<template><div>{{ user.name }}</div> <!-- 直接访问 user.name --><div>{{ list[0] }}</div> <!-- 直接访问数组元素 -->
</template>
3. ref()
与 reactive()
的区别
特性 | ref() | reactive() |
---|---|---|
适用数据类型 | 基本类型、对象、数组 | 仅对象或数组 |
返回值类型 | 带 .value 的对象 | 代理对象(Proxy) |
访问/修改方式 | refValue.value | reactiveObject.property |
模板中使用 | 自动解包,无需 .value | 直接访问属性 |
深度响应式 | 是(若传入对象,内部会调用 reactive ) | 是(嵌套对象/数组自动代理) |
替换整个对象 | 可以(ref.value = newObject ) | 不推荐(直接替换会丢失响应式) |
性能优化 | 基础类型更轻量 | 复杂对象更高效 |
4. 综合示例对比
4.1 场景:计数器
ref()
:const count = ref(0); function increment() {count.value++; }
reactive()
:const state = reactive({ count: 0 }); function increment() {state.count++; }
4.2 场景:表单数据
ref()
:const formData = ref({ name: '', email: '' }); formData.value.name = 'Alice'; // 修改需 .value
reactive()
:const formData = reactive({ name: '', email: '' }); formData.name = 'Alice'; // 修改无需 .value
4.3 场景:动态替换对象
ref()
:const user = ref({ name: 'Alice' }); user.value = { name: 'Bob' }; // 安全替换整个对象
reactive()
:const user = reactive({ name: 'Alice' }); user = reactive({ name: 'Bob' }); // 错误!不能直接替换 reactive 对象
5. 企业级最佳实践
选择原则:
- 基础类型 →
ref()
。 - 对象/数组 →
reactive()
。 - 需要替换整个对象 →
ref()
。 - 嵌套复杂结构 →
reactive()
。
- 基础类型 →
避免陷阱:
- 解构响应式对象:使用
toRefs()
保持响应式。const state = reactive({ count: 0, name: 'Alice' }); const { count, name } = toRefs(state); // 保持响应式
- 大型静态数据:避免用
reactive()
包裹,改用markRaw()
标记非响应式。
- 解构响应式对象:使用
性能优化:
- 高频更新基础类型(如动画帧数) → 优先
ref()
。 - 大型嵌套对象 → 优先
reactive()
。
- 高频更新基础类型(如动画帧数) → 优先
6. 总结
ref()
:适合简单值或需要替换整个对象的场景,使用.value
访问。reactive()
:适合复杂嵌套对象,直接访问属性,代码更简洁。- 核心区别:
ref()
是reactive()
的“包装器”,在处理对象时内部会调用reactive()
,但需要通过.value
操作。
根据实际需求选择合适的 API,可以提升代码的可维护性和性能。