- stop
- effect.spec.ts
核心调用 stop 的时候把对应的dep里的fn 删掉
it("stop", () => {
let dummy
const obj = reactive({prop: 1})
const runner = effect(() => {
dummy = obj.prop
})
obj.prop = 2
expect(dummy).toBe(2)
stop(runner)
obj.prop = 3
expect(dummy).toBe(2)
runner()
expect(dummy).toBe(3)
})
- effect.ts
class ReactiveEffect {
...
+ deps: any = []
+ stop() {
+ this.deps.forEach(dep => {
+ dep.delete(this)
+ })
+ }
}
export function track(target, key) {
...
+ activeEffect.deps.push(dep)
}
export function effect(fn, options: any = {}) {
const _effect = new ReactiveEffect(fn, options.scheduler)
_effect.run()
const runner: any = _effect.run.bind(_effect)
+ runner.effect = _effect
return runner
}
+export function stop(runner) {
+ runner.effect.stop()
+}
- onStop
- effect.sepc.ts
it("onStop", () => {
const obj = reactive({
foo: 1
})
const onStop = jest.fn()
let dummy
const runner = effect(() => {
dummy = obj.foo
}, {
onStop
})
stop(runner)
expect(onStop).toBeCalledTimes(1)
})
- effect.ts
class ReactiveEffect {
onStop?: () => void
stop() {
if (this.active) {
cleanupEffect(this)
if (this.onStop) {
this.onStop()
}
this.active = false
}
}
}
export function effect(fn, options: any = {}) {
const _effect: any = new ReactiveEffect(fn, options.scheduler)
_effect.onStop = options.onStop
...
}
- 优化
之前的代码里
it("stop", () => {
let dummy
const obj = reactive({prop: 1})
const runner = effect(() => {
dummy = obj.prop
})
obj.prop = 2
expect(dummy).toBe(2)
stop(runner)
// obj.prop = 3
obj.prop++
expect(dummy).toBe(2)
runner()
expect(dummy).toBe(3)
})
我如果把 obj.prop = 3换成 obj.prop++ 的话单测就会报错
原因:
obj.prop = 3 是直接 set
而
obj.prop++ 实际上就是 obj.prop = obj.prop + 1 既有 get 又有 set,而触发 get 又重新收集了依赖
let shouldTrack
export function track(target, key) {
...
if(!activeEffect) return
+ if (!shouldTrack) return
...
}
run() {
// 是 stop
+ if (!this.active) {
+ return this._fn()
+ }
// 不是 stop
+ shouldTrack = true
// 把实例对象赋值给 activeEffect
+ activeEffect = this
+ const result = this._fn()
+ shouldTrack = false
+ return result
}
网友评论