实现 effect & reactive & 依赖收集 & 触发依赖

单测

因为 effect 整个测试流程很大,所以拆分出两块,分别是 effect 和 reactive 测试

1
2
3
4
5
6
7
8
9
10
// reactivity/__test__/reactive.spec.ts
import { reactive } from '../reactive'
describe('reactive', () => {
it('happy path', () => {
const original = { foo: 1 }
const observer = reactive(original)
expect(observer).not.toBe(original)
expect(observed.foo).toBe(1)
})
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// reactivity/__test__/effect.spec.ts
import { effect } from '../effect'
import { reactive } from '../reactive'
describe('effect', () => {
it('happy path', () => {
const user = reactive({
age: 10
})
let nextAge
effect(() => {
nextAge = user.age + 1
})
expect(nextAge).toBe(11)
//update
user.age++
expect(nextAge).toBe(12)
})
})

实现单测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//reactivity/reactive.ts
import {track} from './effect';
export const reactive(raw)=>{
return new Proxy(raw,{
get:(target,key)=>{
const res = Reflect.get(target,key);
track(target,key);
return res;
},
set:(target,key,value)=>{
const res = Reflect.set(target,key,value);
trigger(target,key)
return res;
},
})
}
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
//reactivity/effect.ts
let activeEffect //全局变量 接收当前执行effect
class ReactiveEffect {
private _fn: any //私有变量
constructor(fn) {
this._fn = fn
}
run() {
activeEffect = this
this._fn()
}
}
//依赖收集
const targetMap = new Map()
export const track = (target, key) => {
//taget -> key -> dep
let depsMap = targetMap.get(target)
//初始化
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let dep = depsMap.get(key)
if (!dep) {
dep = new Set()
depsMap.set(key, dep)
}
dep.add(activeEffect)
}
//触发依赖
const trigger = (target, key) => {
let depsMap = targetMap.get(target)
let dep = depsMap.get(key)
for (const effect of dep) {
effect.run()
}
}
export const effect = fn => {
const _effect = new ReactiveEffect(fn)
_effect.run()
}