vuex
源码中是在get
钩子函数中进行依赖收集的。在set
钩子函数中触发更新的。在收集依赖时要注意:只会收集effect
中的依赖。
# 1、依赖收集过程
每次获取值的时候就是依赖收集的时候。依赖收集函数track
//baseHandlers.js
//get钩子函数
function createGetter () {
return function get (target, key, receiver) {
const res = Reflect.get(target, key,receiver);
//收集依赖
track(target,TrackOpTypes.GET,key);
if (isObject(res)) {
return reactive(res);
}
return res;
}
}
//effect.js
//依赖收集函数
let targetMap=new WeakMap();//{ {name:'james}:{name:[effect,effect]} }
//依赖收集
export function track(target,type,key){
//如果不是在effect中,不收集依赖
if(activeEffect===undefined) return;
//根据target进行取值
let depsMap=targetMap.get(target);
if(!depsMap){
targetMap.set(target,(depsMap=new Map()));
}
let deps=depsMap.get(key);
if(!deps){
depsMap.set(key,(deps=new Set()))
}
//判断effect中是否已经存在,避免在一个effect中多次获取同一个key的情况
/**
* effect(()=>{
* state.name;
* state.name;//像这种情况就只需要添加一次就行
* })
*/
if(!deps.has(activeEffect)){
deps.add(activeEffect);
activeEffect.deps.push(deps);
}
}
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
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
# 2、触发更新操作
在set
钩子函数中,监听数据变化,当添加数据或者修改数据时,触发更新操作。执行effect
中被监听的属性。依赖更新时,触发更新函数trigger
。
//baseHandlers.js
//set钩子函数
function createSetter () {
//set钩子函数
return function set (target, key, value, receiver) {
// console.log("设置值", key, value)
//要先判断target中是否有这个key了,如果没有就是新增操作,否则就要判断key对应的值跟前面的值是否一样,一样的话,就不用执行下去了
const haskey=hasOwn(target,key);
const oldValue= target[key];//Reflect.get(target,key);
let res=true;
//如果还没有,则需要添加
if(!haskey){
console.log("新增操作")
//新增操作
res = Reflect.set(target, key, value, receiver);
//触发更新
trigger(target,TriggerOpTypes.ADD,key,value);
}else if(hasChanged(oldValue,value)){ //值改变了
//新增操作
res = Reflect.set(target, key, value, receiver);
console.log("修改操作")
//触发更新
trigger(target,TriggerOpTypes.SET,key,value,oldValue);
}
return res;
}
}
//effect.js
//触发更新
export function trigger(target,type,key,value,oldValue){
const depsMap=targetMap.get(target);
if(!depsMap) return;
//触发更新
const run=(effects)=>{
if(effects){
effects.forEach(effect=>effect())
}
}
if(key!==null){
run(depsMap.get(key));
}
if(type===TriggerOpTypes.ADD){
//对数组新增属性,会触发length对应的依赖 因为添加操作时,还没有对响应的key添加依赖
(depsMap.get(Array.isArray(target)?'length':""));
}
}
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
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