Vue 3 的响应式原理可以比喻为"智能监控系统":当数据变化时,它能自动追踪依赖关系并触发更新。以下是通俗解释和核心机制:
一、核心原理:Proxy 代理
Vue 3 的响应式系统基于 JavaScript 的 Proxy
对象实现(Vue 2 使用 Object.defineProperty
)。
Proxy 的优势:
- 支持动态新增属性 (无需
Vue.set
) - 支持数组索引和长度变化
- 性能更好(无需递归遍历对象)
二、实现步骤:如何让数据"活"起来?
1. 创建响应式对象
用 reactive()
包裹普通对象,返回一个 Proxy 代理对象:
javascript
import { reactive } from 'vue';
const state = reactive({
count: 0,
list: ['Apple', 'Banana']
});
Proxy 的拦截行为:
- 当你访问
state.count
(get
操作)→ 收集依赖(记录谁在用这个值)。 - 当你修改
state.count
(set
操作)→ 触发更新(通知依赖它的地方更新)。
2. 依赖收集(Tracking Dependencies)
当模板或计算属性访问响应式数据时,Vue 会记录这个关系:
vue
<template>
<div>{{ state.count }}</div> <!-- 访问 state.count → 建立依赖 -->
</template>
原理:
- 通过
effect
函数(类似"监听器")包裹需要响应式执行的代码。 - 当代码执行时,所有被访问的响应式属性会自动收集当前
effect
作为依赖。
3. 触发更新(Triggering Updates)
当数据变化时,Proxy 的 set
拦截器会找到所有关联的 effect
并重新执行它们:
javascript
state.count = 10; // 触发 set → 通知所有依赖的 effect 更新
三、核心 API 的差异
1. reactive
vs ref
-
reactive
:针对对象(Object、Array)的深度代理。javascriptconst obj = reactive({ a: 1 });
-
ref
:针对基本类型(string、number、boolean),通过.value
访问。javascriptconst count = ref(0); console.log(count.value); // 0
为什么需要
ref
:Proxy 无法直接代理基本类型,
ref
将值包装在{ value: ... }
对象中,再对这个对象做响应式处理。
2. effect
函数
Vue 内部通过 effect
实现依赖追踪和更新触发(开发者通常通过 watch
或 computed
间接使用):
javascript
import { effect } from 'vue';
effect(() => {
console.log('count变化了:', state.count); // 自动追踪 state.count
});
四、简单实现(极简版)
javascript
// 极简响应式系统
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key); // 收集依赖
return target[key];
},
set(target, key, value) {
target[key] = value;
trigger(target, key); // 触发更新
return true;
}
});
}
// 依赖收集和触发
let activeEffect = null;
const depsMap = new Map();
function track(target, key) {
if (activeEffect) {
let dep = depsMap.get(target)?.get(key);
if (!dep) {
dep = new Set();
depsMap.set(target, (depsMap.get(target) || new Map()).set(key, dep));
}
dep.add(activeEffect);
}
}
function trigger(target, key) {
const dep = depsMap.get(target)?.get(key);
dep?.forEach(effect => effect());
}
function effect(fn) {
activeEffect = fn;
fn(); // 首次执行以收集依赖
activeEffect = null;
}
五、关键特点
-
嵌套对象自动代理
reactive
会递归代理对象的所有嵌套属性。 -
懒代理
Vue 3 不会立即代理所有属性,只有被访问到的属性才会被代理(性能优化)。
-
数组处理优化
直接通过索引修改数组或修改
length
属性也能触发更新。
六、开发者注意事项
-
避免解构响应式对象
解构会破坏代理关系,导致失去响应性:
javascriptconst { count } = state; // ❌ 错误!count 不再是响应式的 const count = ref(state.count); // ✅ 正确
-
使用
toRefs
保持响应性解构时保持响应式:
javascriptimport { toRefs } from 'vue'; const { count } = toRefs(state); // 通过 .value 访问
七、总结
Vue 3 的响应式系统像一个"智能摄像头":
- 监控数据访问 (
get
):记录谁在关注这个数据。 - 监控数据修改 (
set
):通知所有关注者更新。 - 自动化管理依赖:开发者只需关注数据变化,视图自动同步。
通过 Proxy
的强大能力,Vue 3 解决了 Vue 2 的诸多限制(如数组和新增属性的响应问题),同时提升了性能和开发体验。