在 Vue 3 中,ref 和 reactive 是实现响应式数据的核心 API,它们基于 Proxy 实现,但适用场景和使用方式有所不同。以下从原理、使用方法和核心区别三个方面详细说明:
一、原理:基于 Proxy 的响应式实现
Vue 3 的响应式系统通过 ES6 Proxy 实现,相比 Vue 2 的 Object.defineProperty,Proxy 能拦截对象的所有操作(如新增属性、删除属性、数组索引修改等),天然支持更全面的响应式场景。
reactive直接对对象 / 数组创建 Proxy 代理,拦截其读写操作。ref则是对基本类型(如 Number、String)或复杂类型进行包装,内部通过一个包含value属性的对象实现响应式,本质上也是基于 Proxy。
二、使用方法
1. reactive:处理对象 / 数组类型
作用:将对象或数组转为响应式数据,直接操作原对象的属性即可触发更新。注意:
- 只能传入对象或数组,传入基本类型(如
reactive(123))会报警告且不生效。 - 不能直接替换整个对象,否则会丢失响应式:
// 错误:替换后 user 不再是响应式对象 user = reactive({ name: '李四' });
2. ref:处理基本类型或复杂类型
作用:将基本类型(Number、String、Boolean 等)或复杂类型转为响应式数据,通过 .value 访问和修改值。
import { ref } from 'vue';
// 基本类型
const count = ref(0);
const message = ref('Hello');
// 复杂类型(对象/数组也可以用 ref)
const user = ref({ name: '张三' });
const list = ref([1, 2, 3]);
// 修改值(必须通过 .value)
count.value++; // 视图会更新
message.value = 'World'; // 视图会更新
// 修改复杂类型的属性(两种方式均可)
user.value.age = 20; // 方式1:通过 .value 访问对象
list.value.push(4); // 方式1:通过 .value 访问数组
// 注意:替换整个复杂类型时,响应式仍保留
user.value = { name: '李四' }; // 有效,仍为响应式
注意:
- 在 模板中使用
ref时,Vue 会自动解包(无需写.value)<template> <p>{{ count }}</p> <!-- 直接用 count,无需 count.value --> </template> - 在
setup函数或组合式 API 中,必须通过.value访问。
三、核心区别
| 维度 | reactive | ref |
|---|---|---|
| 处理类型 | 仅支持对象 / 数组 | 支持基本类型(number/string 等)和复杂类型 |
| 访问方式 | 直接访问属性(如 user.name) | 需通过 .value 访问(模板中自动解包) |
| 替换数据 | 不能直接替换整个对象(会丢失响应式) | 可直接替换 .value(响应式保留) |
| 解构赋值 | 解构后会丢失响应式(需用 toRefs) | 解构时需保留 .value 才能维持响应式 |
| 适用场景 | 复杂对象 / 数组的响应式管理 | 基本类型、单个值的响应式管理,或需要频繁替换的复杂类型 |
关键差异解析:
-
类型支持:
reactive只能处理对象 / 数组,这是最核心的限制;ref无类型限制,万能但对对象 / 数组本质是包装成{ value: 对象 }。
-
访问方式:
reactive操作直观(直接点语法),但面对基本类型无能为力;ref需用.value,稍显繁琐,但统一了所有类型的响应式处理方式。
-
解构与响应式保留:
- 对
reactive对象解构时,属性会失去响应式,需用toRefs转换:import { reactive, toRefs } from 'vue'; const user = reactive({ name: '张三', age: 20 }); const { name, age } = toRefs(user); // 解构后仍为响应式(ref 类型) - 对
ref解构时,直接解构会丢失响应式,需保留.value或用toRef:const count = ref(0); const { value: countVal } = count; // 需显式获取 .value
- 对
四、使用建议
- 基本类型(如数字、字符串):优先用
ref(reactive不支持)。 - 简单对象 / 数组:若无需替换整个对象,用
reactive更直观;若需要频繁替换(如重置数据),用ref更方便。 - 复杂业务场景:推荐用
ref统一管理,避免reactive的解构问题(尤其在组合式 API 中,ref更易与setup函数的返回值配合)。
例如,在组件中:
// 推荐:用 ref 统一管理
const user = ref({ name: '张三' });
const age = ref(20);
const list = ref([1, 2, 3]);
// 后续可直接替换
user.value = { name: '李四' }; // 安全且简单
总结
reactive 和 ref 都是基于 Proxy 实现的响应式 API,核心区别在于:
reactive面向对象 / 数组,操作直观但有类型限制;ref面向所有类型,通过.value访问,更灵活通用。
实际开发中,ref 因其普适性(支持所有类型)和灵活性(可直接替换值),使用频率往往更高,尤其是在 Vue 3 的组合式 API 中。
注:用于自己学习,查看

1631

被折叠的 条评论
为什么被折叠?



