reactive API
Vue 3 的 reactive API 是响应式系统的核心,基于 ES6 的 Proxy 实现,专为对象类型数据提供深层响应式能力。以下从原理、用法、局限性和进阶技巧全面解析:
⚙️ 一、核心原理与实现
-
Proxy 代理机制
reactive将普通对象包装为 Proxy 代理对象,通过拦截属性的 读取(get) 和 设置(set) 操作实现响应式:- 依赖收集(track):读取属性时,记录当前依赖的副作用函数(如视图更新函数)。
- 触发更新(trigger):修改属性时,通知所有依赖执行更新。
const state = reactive({ count: 0 }); state.count++; // 触发 set 拦截器 → 更新视图 -
深层响应式
嵌套对象的属性也会被自动转换为响应式:const state = reactive({ user: { name: 'Tom' } }); state.user.name = 'Jerry'; // 深层属性修改仍触发更新 -
缓存优化
通过WeakMap缓存原始对象与代理对象的映射,避免重复代理同一对象:const raw = {}; const proxy1 = reactive(raw); const proxy2 = reactive(raw); // 返回 proxy1,避免重复创建
🛠️ 二、使用方式与特性
基础用法
import { reactive } from 'vue';
const state = reactive({
count: 0,
list: [1, 2, 3],
});
state.list.push(4); // 数组变更自动响应
自动解包 ref
当 reactive 对象的属性值是 ref 时,模板和脚本中访问会自动解包(无需 .value):
const num = ref(10);
const state = reactive({ num });
console.log(state.num); // 10(自动解包)
与 ref 的对比
| 特性 | reactive | ref |
|---|---|---|
| 适用类型 | 对象/数组/集合类型 | 基本类型 + 对象类型(需 .value) |
| 访问方式 | 直接访问属性(state.count) | 需 .value(脚本中) |
| 重赋值 | ❌ 整体替换丢失响应性 | ✅ 支持(.value = newObj) |
| 解构响应性 | ❌ 需配合 toRefs | ✅ 直接解构有效 |
何时用
reactive?
- 管理关联数据(如表单对象)
- 无需整体替换的场景(如配置对象)
- 需深层嵌套响应(如用户信息对象)
⚠️ 三、局限性及解决方案
-
仅支持对象类型
原始类型(如string/number)不可用reactive,需用ref:const count = reactive(0); // 警告:参数必须是对象! -
解构丢失响应性
直接解构会失去响应连接:const state = reactive({ count: 0 }); const { count } = state; // count 是普通值,非响应式!✅ 解决方案:
import { toRefs } from 'vue'; const state = reactive({ count: 0 }); const { count } = toRefs(state); // count 转为 ref,保持响应 -
不可整体替换
重赋值会破坏响应式:let state = reactive({ count: 0 }); state = { count: 1 }; // ❌ 新对象无响应性✅ 正确做法:
// 修改属性而非替换对象 Object.assign(state, { count: 1 }); // ✅ 保持响应
🔧 四、进阶技巧与相关 API
1. 浅层响应式(shallowReactive)
仅代理对象的第一层属性,深层属性不变为响应式,适合性能敏感场景:
import { shallowReactive } from 'vue';
const state = shallowReactive({ user: { name: 'Tom' } });
state.user.name = 'Jerry'; // ❌ 不触发更新(深层非响应)
state.user = { name: 'Jerry' }; // ✅ 触发更新(第一层响应)
2. 只读代理(readonly)
禁止修改响应式对象:
const state = reactive({ count: 0 });
const readOnlyState = readonly(state);
readOnlyState.count = 1; // ❌ 控制台警告,修改失败
3. 原始对象获取(toRaw)
绕过 Proxy 直接操作原始对象,避免触发更新:
const raw = toRaw(state); // 获取 state 的原始对象
raw.count = 100; // 修改不触发视图更新
💡 五、最佳实践
- 优先
const声明:避免意外重赋值。 - 复杂对象扁平化:减少深层嵌套提升性能。
- 配合
computed/watch:实现派生数据与副作用逻辑:const double = computed(() => state.count * 2); watch(() => state.count, (newVal) => { /* ... */ }); - 避免与
ref混用:对象属性推荐全用reactive,基本类型用ref。
💎 总结
reactive 是 Vue 3 响应式系统的基石,通过 Proxy 代理、深层响应和 ref 自动解包 简化对象类型数据管理。其局限可通过 toRefs 解构、shallowReactive 优化性能等方式规避。实践中,关联数据用 reactive,独立数据用 ref,结合计算属性与侦听器构建高效响应式逻辑。
评论