vue3的api解读-effect scope

文章详细介绍了Vue中的effectScope概念,用于管理组件内的副作用,如watch和watchEffect。通过示例展示了如何使用effectScope创建作用域并控制其中的效果,包括在特定条件下启动和停止副作用,以及在组件卸载时清理资源。此外,还讨论了在处理MouseMove事件时使用effectScope的场景,以及不使用scope的替代方案。
摘要由CSDN通过智能技术生成

什么是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(),提供个开关就可以了
    • 这样的场景多不多?很少
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值