实现 effect 的 stop 功能

//effect.spec
 it('stop', () => {
        let dummy
        const obj = reactive({ prop: 1 })
        const runner = effect(() => {
            dummy = obj.prop
        })
        obj.prop = 2
        expect(dummy).toBe(2)
        // stop 一个 runner 之后
        stop(runner)
        obj.prop++
        // 依赖再次更新,当时传入的 effect 则不会重新执行
        expect(dummy).toBe(2)
        // runner 不受到影响
        runner()
        expect(dummy).toBe(3)
    })
//effect.ts
let activeEffect
let shouldTrack 
const targetMap = new WeakMap()

class ReactiveEffect{
    private _fn
    deps=[]
    active= true
    constructor(fn,public scheduler?){
        this._fn = fn
    }
    run(){
        if (!this.active) {
            return this._fn();
          }
      
          // 应该收集
          shouldTrack = true;
          activeEffect = this;
          const r = this._fn();
      
          // 重置
          shouldTrack = false;
      
          return r;
    }
    stop(){
        if (this.active) {
            cleanupEffect(this)     
        }   
        this.active = false
    }
}



function cleanupEffect(effect){
    effect.deps.forEach((dep: any) => {
        dep.delete(effect)
      })
}

export function track(target, key){
    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)
    }
    //判断是否应该收集,stop过的shouldTrack为false
    if(activeEffect&&shouldTrack){
        activeEffect.deps.push(dep)
        dep.add(activeEffect)
    }   
}

export function trigger(target, key){
    let depsMap = targetMap.get(target)
    let deps = depsMap.get(key)
    for(const effect of deps){
        if(effect.scheduler){
            effect.scheduler()
        }else{
            effect.run()
        }   
    }
}

export function effect(fn,option:any={}){
    const _effect = new ReactiveEffect(fn,option.scheduler)
    _effect.run();
    let runner:any = _effect.run.bind(_effect)
    runner.effect = _effect

    return runner
 }

 export function stop(runner){ 
    runner.effect.stop()
 }

ohoherror
21 声望1 粉丝