在 Vue 3 的 Composition API 中,ref
和 reactive
都用于创建响应式数据,但它们在设计目的、使用方式和适用场景上有明显区别:
**ref
**
javascript复制const count = ref(0); // 数字类型const message = ref('Hello'); // 字符串类型
可处理任意类型的值(原始值、对象、数组等)。
常用于定义基本类型(如 string
、number
、boolean
)的响应式数据。
**reactive
**
javascript复制const user = reactive({ name: 'Alice', age: 30 }); // 对象类型const list = reactive([1, 2, 3]); // 数组类型
仅处理对象类型(Object、Array、Map、Set 等)。
常用于定义复杂对象或数组的响应式数据。
**ref
**
javascript复制const count = ref(0);console.log(count.value); // 0count.value = 1; // 修改值
html运行复制<!-- 模板中直接使用 --><div>{{ count }}</div>
通过 .value
属性访问或修改值(模板中自动解包,无需 .value
)。
**reactive
**
javascript复制const user = reactive({ name: 'Alice' });console.log(user.name); // 'Alice'user.name = 'Bob'; // 直接修改属性
直接通过属性访问或修改(无需 .value
)。
**ref
**
javascript复制// ref 的简化实现function ref(value) { return reactive({ value });}
内部通过 reactive
包装成一个对象,将值存储在 value
属性中。
本质是一个包含 value
属性的响应式对象。
**reactive
**
基于 ES6 的 Proxy
实现,递归地将对象的所有属性转为响应式。
直接代理原始对象,嵌套属性也保持响应性。
**ref
更通用**
需要处理基本类型时(如数字、字符串)。
需要将变量传递给函数或解构时(保持响应性)。
需要明确区分响应式变量和非响应式变量(通过 .value
显式操作)。
**reactive
更适合复杂对象**
需要定义一个嵌套结构的响应式对象(如用户信息、表单数据)。
需要直接修改属性(避免频繁使用 .value
)。
**ref
的陷阱**
在 JavaScript 中必须使用 .value
操作(模板中例外)。
若用 ref
包装对象,内部会调用 reactive
,因此等价于 reactive
。
**reactive
的陷阱**
javascript复制const user = reactive({ name: 'Alice' });const { name } = user; // ❌ 解构后失去响应性const { name } = toRefs(user); // ✅ 保持响应性(通过 `name.value` 访问)
直接解构会失去响应性!需配合 toRefs
保持响应性。
特性 | ref | reactive |
---|---|---|
支持数据类型 | 任意类型 | 仅对象类型(Object、Array 等) |
访问方式 | 通过 .value (模板中自动解包) | 直接访问属性 |
响应式实现 | 包装为 { value: ... } 对象 | 直接代理原始对象 |
适用场景 | 基本类型、需要传递或解构的变量 | 复杂对象、嵌套数据 |
解构响应性 | 保持响应性 | 需配合 toRefs 保持响应性 |
优先用 ref
:处理基本类型、需要灵活传递或解构变量时。
优先用 reactive
:处理复杂对象、嵌套数据,且不需要频繁解构时。
两者可结合使用:例如用 reactive
管理对象,用 ref
引用对象的某个属性。