在 Vue3 中,ref 和 reactive 是两个核心的响应式 API,用于创建响应式数据。它们在功能和使用场景上存在显著差异。
ref
-
适用类型:基本数据类型(如数字、字符串、布尔值)和对象/数组(但需通过 .value 访问)
-
特点:返回一个包装对象,通过 .value 获取/修改值。
-
示例:
import { ref } from 'vue';
const count = ref(0); // 基本类型
const user = ref({ name: 'John' }); // 对象
console.log(count.value); // 0
user.value.name = 'Jane'; // 修改对象属性
reactive
-
适用类型:对象/数组(直接访问属性)
-
特点:返回一个 Proxy 对象,直接通过属性名访问/修改。
-
示例:
import { reactive } from 'vue';
const state = reactive({ count: 0, user: { name: 'John' } });
console.log(state.count); // 0
state.user.name = 'Jane'; // 修改嵌套属性
| ref | reactive | |
|---|---|---|
| ###### 返回值类型 | 包装对象(需 .value 访问) | Proxy对象(直接访问属性) |
| ###### 适用场景 | 简单数据类型(如数字、字符串)或对象、数组(需: .value) | 复杂对象、数组(直接访问属性) |
| ###### 响应式原理 | 通过 .value 访问时收集依赖,修改时触发更新 |
通过 Proxy 拦截属性访问/修改,自动追踪依赖 |
| ###### 解构问题 | 解构后失去响应性(需使用 toRefs 解决) |
解构后保持响应性(无需额外处理) |
| ###### 嵌套对象 | 对象内部属性需通过 .value 访问(如 user.value.name) |
嵌套对象自动保持响应性(如 state.user.name) |
使用建议:
选择依据:
- 简单数据: 优先使用 ref(如计数器、标志位)
- 复杂对象:优先使用 reactive(如用户状态、配置项)
注意事项:
- ref 对象在模板中自动解包(无需 .value),但在脚本中需显式访问
- reactive 返回的 Proxy 对象与原始对象不相等(需通过 isProxy 检查)
- 避免在 ref 中直接赋值新对象(会失去响应性),可使用 Object.assign 替换
高级用法
###### shallowRef/shallowReactive:
* 创建浅层响应式对象(仅顶层响应性)
###### toRefs:
* 将 reactive 对象解构为响应式引用(避免解构丢失响应性)
###### watch 监听:
* ref 需通过 .value 访问(如 watch(count, (newVal) =\> { ... }))。
- 优先选择:
- 简单数据 → ref
- 复杂对象 → reactive
- 关键区别:
- ref 需 .value 访问,reactive 直接访问属性
- ref 解构后需 toRefs 保持响应性,reactive 自动保持
通过合理选择和使用 ref/reactive,可高效构建 Vue3 的响应式系统