stop的功能:当我们更新响应式值时会触发响应式,更新对应的值,如果不想触发更新可以使用stop,即把对应的依赖删除掉即可
单元测试:
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);
// stopped effect should still be manually callable
runner();
expect(dummy).toBe(3);
js源码:
class ReactiveEffect{
private _fn:any;
deps = [];
active = true;
OnStop?: () => void;
public scheduler:Function | undefined
constructor(fn,scheduler?:Function){
this._fn = fn;
this.scheduler = scheduler;
}
run(){
activeEffect = this;
return this._fn();
}
stop(){
if(this.active){
cleanupEffect(this);
if(this.onStop){
this.onStop();
}
this.active = false;
}
}
const targetMap = new Map();
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);
}
if(!activeEffect) return;
dep.add(activeEffect);
// 反向收集deps
activeEffect.deps.push(dep);
}
export function trigger(target, key){
let depsMap = targetMap.get(target);
let dep = depsMap.get(key);
for(const effect of dep){
if(effect.scheduler){
effect.scheduler();
} else {
effect.run();
}
}
export function cleanupEffect(effect:any){
effect.deps.forEach(dep => {
dep.delete(effect);
}
}
let activeEffect;
export function effect(fn, options:any=[]){
const _effect = new reactiveEffect(fn, options.scheduler);
// 接收onStop参数
// _effect.onStop = options.onStop;
// 这样写更优雅
Object.assign(_effect, options);
_effect.run();
const runner = _effect.run.bind(_effect);
// 先挂载下effect
runner.effect = _effect;
return runner;
}
export function stop(runner){
runner.effect.stop();
}