什么是scope
- 英文:范围
- 举例:变量的可见范围(variable scope)
- 举例:闭包内变量的可见范围是词法作用域(lexical scope)
- 举例:slot-scope绑定的变量的可见范围是template内部
effect scope
- 人为设置一个范围,对其内部的所有effect进行管理【可见,集中处理】
const scope = effectScope()
scope.run(()=>{
// 副作用1
const doubled = computed(()=> couter.value * 2)
// 副作用2
watch(doubled, ()=> console.log(doubled.value))
// 副作用3
watchEffect(() => 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.clientX
point.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 = null
const 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() { // 更好的封装,不用scope
const point = reactive({ x: 0, y: 0 })
const active = ref(false)
function handler(e: MouseEvent) {
point.x = e.clientX
point.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 = null
return () => {
return <div>
{active.value && <span> point is : {x.value}, {y.value}</span>}
<button onClick={() => {
active.value = !active.value
}}>toogle</button>
</div>
}
}
})
- 思考:
- 这个场景不用Scope行不行?可以呀,在useMouseMove(),提供个开关就可以了
- 这样的场景多不多?很少