什么是scope
- 英文:范围
- 举例:变量的可见范围(variable scope)
- 举例:闭包内变量的可见范围是词法作用域(lexical scope)
- 举例:slot-scope绑定的变量的可见范围是template内部
effect scope
- 人为设置一个范围,对其内部的所有effect进行管理【可见,集中处理】
const scope = effectScope()
scope.run(()=>{// 副作用1const doubled = computed(()=> couter.value * 2) // 副作用2watch(doubled, ()=> console.log(doubled.value))// 副作用3watchEffect(() => console.log('Count:', doubled.value))
})// to dispose all effects in the scope;
// 处理范围中的所有效果; 一次性注销掉副作用1, 2, 3
scope.stop()
effect scope示例讲解
effect scope的用法【使用场景比较窄】
- Coding:实现控制MouseMove事件的开关
/src/examples/ScopeExamples.tsx
import {defineComponent,effectScope,watch,watchEffect,ref,reactive,toRefs,onUnmounted,// 组件卸载时候的钩子onScopeDispose,
} from "vue"
import type {Ref,EffectScope
} from "vue"
export const ScopeExample01 = defineComponent({setup() {// 如果第一个参数传true,那就不听父域的管了。const scope = effectScope()const c = ref(0)scope.run(() => {watch(c, () => {console.log('watch effect', c.value)})})setInterval(() => {c.value++}, 300)setTimeout(() => {scope.stop()}, 2000)return () => {return <div>{c.value}</div>}}
})
export const ScopeExample02 = defineComponent({setup() {const scope = effectScope()const c = ref(0)scope.run(() => {const subScope = effectScope() // 可以嵌套subScope.run(() => {watch(c, () => {console.log('watch effect', c.value)})})})setInterval(() => {c.value++}, 300)setTimeout(() => {// 父域作用停止,子域也停止// 如果第一个参数传true,那就不听父域的管了。// effectScope(true)scope.stop()}, 2000)return () => {return <div>{c.value}</div>}}
})
function useMouseMove() {const point = reactive({ x: 0, y: 0 })function handler(e: MouseEvent) {point.x = e.clientXpoint.y = e.clientY}window.addEventListener("mousemove", handler)onScopeDispose(() => { // scope.stop(),就会执行它window.removeEventListener("mousemove", handler)})return toRefs(point)
}
export const ScopeExample03 = defineComponent({setup() {let point: {x: Ref<number>,y: Ref<number>} | null = null // point开始是null所以第一次渲染没有存依赖let scope: EffectScope | null = nullconst active = ref(false)watch(active, () => {if (active.value) {scope = effectScope()point = scope.run(() => {return useMouseMove()})! // 后面这个!是断言不可能为null} else {scope?.stop() // 存在,就停止point = null}})return () => {return <div>{active.value && <span> point is : {point?.x.value}, {point?.y.value}</span>}<button onClick={() => {active.value = !active.value}}>toogle</button></div>}}
})
function useMouseMove1() { // 更好的封装,不用scopeconst point = reactive({ x: 0, y: 0 })const active = ref(false)function handler(e: MouseEvent) {point.x = e.clientXpoint.y = e.clientY}watch(active, () => {if (active.value) {window.addEventListener("mousemove", handler)} else {window.removeEventListener("mousemove", handler)}})return {...toRefs(point),active}
}
export const ScopeExample04 = defineComponent({setup() {const { x, y, active } = useMouseMove1() // point开始是null所以第一次渲染没有存依赖let scope: EffectScope | null = nullreturn () => {return <div>{active.value && <span> point is : {x.value}, {y.value}</span>}<button onClick={() => {active.value = !active.value}}>toogle</button></div>}}
})
- 思考:
- 这个场景不用Scope行不行?可以呀,在useMouseMove(),提供个开关就可以了
- 这样的场景多不多?很少