认识
2024年03月20日
一、认识
effectScope
创建一个 effect
作用域,可以捕获其中所创建的响应式副作用 (即计算属性和侦听器),这样捕获到的副作用可以一起处理。开发者自己来收集副作用成本较高, 可能也会忘记收集,造成内存泄漏等。因此, 提供了一个 effectScope
帮助我们收集、清理副作用。
1.1 手动收集
import { ref,stop,computed, watch, watchEffect } from 'vue';
let disposables = [];
const count = ref(0);
const doubleCount = computed(()=> count.value * 2);
disposables.push(()=> stop(doubleCount));
const watchCount = watch(()=> count.value, ()=> console.log("watch count", count.value));
disposables.push(watchCount);
const watchEffectCout = watchEffect(()=> console.log('watchEffect count', count.value));
disposables.push(watchEffectCout);
const watchDoubleCount = watch(()=> doubleCount.value, ()=> console.log("watch doubleCount", doubleCount.value));
disposables.push(watchDoubleCount);
const watchEffectDoubleCount = watchEffect(()=> console.log('watchEffect doubleCount', doubleCount.value));
disposables.push(watchEffectDoubleCount);
setTimeout(()=>{
count.value++;
},2000);
setTimeout(()=>{
disposables.forEach(dispose=> dispose());
disposables = []
},4000);
setTimeout(()=>{
count.value++;
}, 60000);
二、语法
2.1 单层 effectScope
const counter = ref(2);
const scope = effectScope();
scope.run(() => {
const doubled = computed(() => counter.value * 2);
watch(doubled, () => console.log("watch:", doubled.value));
watchEffect(() => console.log("watchEffect:", doubled.value));
});
setTimeout(() => {
counter.value = 3; // 更改 counter 的值,会触发 watch 和 watchEffect
}, 1000);
setTimeout(() => {
scope.stop(); // 停止掉 scope 作用域内的所有 effect 副作用
}, 3000);
setTimeout(() => {
counter.value = 5; // 再次更改 counter 的值,但是由于 scope 已经停止,所以不会触发 watch 和 watchEffect
}, 5000);
2.2 子父 effectScope
effectScope(detached)
中 detached
表示是否阻断和父级的联系, 若为 true
则表示与父级断开关联,执行父级stop
方法时会递归停止子集的监听,但子集detached
为true
时则不会停止。
const counter = ref(2);
let nestedScope;
let childScope;
const parentScope = effectScope(); // 创建 parentScope 作用域
parentScope.run(() => {
const doubled = computed(() => counter.value * 2);
nestedScope = effectScope(true); // 创建 nestedScope 作用域, 但是与父级断开连接, 不会受到父级的影响
nestedScope.run(() => {
watch(counter, () => console.log("nestedScope watch:", counter.value));
watch(doubled, () => console.log("nestedScope watch:", doubled.value));
watchEffect(() => console.log("nestedScope watchEffect:", doubled.value));
});
childScope = effectScope(); // 创建 childScope 作用域, 与父级连接, 会受到父级的影响
childScope.run(() => {
watch(counter, () => console.log("childScope watch:", counter.value));
watch(doubled, () => console.log("childScope watch:", doubled.value));
watchEffect(() => console.log("childScope watchEffect:", doubled.value));
});
watch(counter, () => console.log("parentScope watch:", counter.value));
watch(doubled, () => console.log("parentScope watch:", doubled.value));
});
setTimeout(() => {
counter.value = 3; // 更改 counter 的值,会触发 parentScope、childScope、nestedScope 中的 watch 和 watchEffect
}, 1000);
setTimeout(() => {
parentScope.stop(); // 停止掉 parentScope 作用域内的所有 effect 副作用, 这时候包括 childScope 作用域内的副作用也会停止。因为 nestedScope 作用域与 parentScope 断开连接,所以不会受到影响
}, 3000);
setTimeout(() => {
counter.value = 5; // 再次更改 counter 的值,但是由于 parentScope 已经停止,所以不会触发 parentScope 和 childScope 中 watch 和 watchEffect 的副作用, 但是 nestedScope 作用域中的副作用会触发
}, 5000);
setTimeout(() => {
nestedScope.stop(); // 停止掉 nestedScope 作用域内的所有 effect 副作用
}, 7000);
setTimeout(() => {
counter.value = 5; // 再次更改 counter 的值,但是由于 nestedScope 已经停止,所以不会触发 nestedScope 中 watch 和 watchEffect 的副作用
}, 9000);
2.3 effectScope 停止回调
effectScope
停止监听时触发改函数 onScopeDispose
,作用类似onUnmounted
。注意: onScopeDispose
必须放在 run
回调函数中才会触发。
onst counter = ref(2);
const scope = effectScope();
scope.run(() => {
const doubled = computed(() => counter.value * 2);
watch(doubled, () => console.log("watch:", doubled.value));
watchEffect(() => console.log("watchEffect:", doubled.value));
onScopeDispose(() => {
console.log("scope disposed");
});
});
setTimeout(() => {
counter.value = 3; // 更改 counter 的值,会触发 watch 和 watchEffect
}, 1000);
setTimeout(() => {
scope.stop(); // 停止掉 scope 作用域内的所有 effect 副作用
}, 3000);
setTimeout(() => {
counter.value = 5; // 再次更改 counter 的值,但是由于 scope 已经停止,所以不会触发 watch 和 watchEffect
}, 5000);