vue-vue3的响应式原理的理解
Vue 3 的依赖收集核心是基于 Proxy。读取数据时(触发 get),通过 track 函数把当前的副作用函数(如组件渲染函数)收集起来;在修改数据时(触发 set),通过 trigger 函数找到并执行这些副作用函数。
1. 核心总结
“Vue 3 的响应式系统是基于 Proxy 实现的。它包含两个核心过程:
- 依赖收集 (
track):发生在读取数据(get)时,将当前的副作用函数(如组件渲染函数)存储起来。- 派发更新 (
trigger):发生在修改数据(set)时,取出之前收集的副作用函数并执行,从而更新视图。”
2. 核心数据结构 (TargetMap)
Vue 3 使用了一个全局的
WeakMap(targetMap)存依赖:
WeakMap的 Key 是原始对象 (Target)。- Value 是一个
Map(depsMap),它的 Key 是属性名。depsMap的 Value 是一个Set(dep),里面存放着所有相关的副作用函数 (Effect)。简单说就是:
Target->Key->Effect集合。”
3. 详细流程解析
阶段一:依赖收集 (Track) - “读的时候记账”
- 当我们在组件渲染或计算属性中读取
state.count时,触发 Proxy 的get拦截。 get内部调用track(target, key)。track函数会检查全局变量activeEffect(当前正在运行的副作用)。- 如果有,就去
targetMap中找到对应的Set,把activeEffect加进去。
阶段二:派发更新 (Trigger) - “写的时候通知”
- 当我们执行
state.count = 2时,触发 Proxy 的set拦截。 set内部首先通过Reflect.set更新数据值。- 然后调用
trigger(target, key)。 trigger函数通过target和key去targetMap中查找,找到对应的Set(依赖集合)。- 遍历这个
Set,执行里面所有的副作用函数,视图因此更新。
📊 完整原理图解

💻 简版源码
这段代码展示了从 reactive 到 track 再到 trigger 的完整逻辑。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// --- 1. 全局变量 & 副作用函数 ---
let activeEffect = null;
function effect(fn) {
activeEffect = fn;
fn(); // 执行 fn,触发 get -> 触发 track
activeEffect = null;
}
// --- 2. 依赖存储结构 ---
// WeakMap { Target -> Map { Key -> Set [Effect] } }
const targetMap = new WeakMap();
// --- 3. 依赖收集 (Track) ---
function track(target, key) {
if (!activeEffect) return;
// 1. 找 target 对应的 depsMap
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
// 2. 找 key 对应的 dep (Set)
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
// 3. 收集当前副作用
dep.add(activeEffect);
}
// --- 4. 派发更新 (Trigger) ---
function trigger(target, key) {
// 1. 也就是根据 target 和 key 找到 dep
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(key);
// 2. 执行所有依赖 (构造新的 Set 防止循环引用问题)
if (dep) {
const effectsToRun = new Set(dep);
effectsToRun.forEach(effectFn => effectFn());
}
}
// --- 5. 响应式核心 (Reactive) ---
function reactive(target) {
return new Proxy(target, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
// 关键:收集依赖
track(target, key);
return result;
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
// 关键:触发更新 (注意:要在 set 成功之后)
trigger(target, key);
return result;
}
});
}
// --- 测试 ---
const state = reactive({ count: 0 });
effect(() => {
console.log('视图渲染:', state.count);
});
// 控制台输出: "视图渲染: 0" (初始化触发 get -> track)
state.count++;
// 控制台输出: "视图渲染: 1" (修改触发 set -> trigger)