问题描述
在看一个setTimeout的逻辑, 如图:
发现有个问题, 需要在组件卸载时, 终止timer的运行, 自然就想到了vueuse里面的useTimeoutFn, 优化后如图:
看了下useTimeoutFn的实现, 看到通过getCurrentScope()如图
做的 timer 清理的绑定.
getCurrentScope()在组件顶层作用域返回EffectScope对象, 因为在异步执行域里面返回值是 undefined, 所以, 直接把useTimeoutFn写在异步的getImgList()里面, 定时器不会自动停止的原因.
EffectScope 是什么
对于EffectScope的解释参考rfcs/active-rfcs/0041-reactivity-effect-scope.md.
概括来说通过EffectScope, 可以自动收集当前所有的响应式监听, 即watchEffect,watch等, 也可以统一的关闭释放这些监听.
EffectScope对象的方法:
-
run(): 绑定响应式, 可多次调用, 但是在调用
stop()后, 再调用run()无效. -
stop(): 停止
EffectScope对象, 并触发onScopeDispose()绑定的回调
EffectScope相关的函数:
- getCurrentScope(): 获取当前的
EffectScope - effectScope(): 创建一个自定义的
EffectScope - onScopeDispose(): 绑定在
EffectScope停止时的回调.
如何在异步作用域绑定响应式
要在异步作用域绑定响应式, 需要先在组件的顶层作用域获取EffectScope对象: const __curScope = getCurrentScope();
然后, 在异步逻辑里面通过__curScope.run()绑定:
__curScope.run({
const s = new Date().toLocaleTimeString();
//这个在组件卸载时,不能自动清除timer
setInterval(() => {
console.log("setInterval", s);
}, 1000);
//这个在组件卸载时,自动清除timer
useIntervalFn(() => {
console.log("useIntervalFn", s);
}, 1000);
});