Skip to content

Vue3 EffectScope理解

2024-08-19

# effectScope使用

1. API说明

effectScope,这个API允许开发者在一个同步函数中自动收集副作用(如计算属性和侦听器),并在稍后的时间一起处理它们

2. API设计动机

在Vue组件的setup()中,副作用会被收集并绑定到当前实例。当实例卸载时,副作用会自动处理。这是一个方便且直观的特性。

然而,当我们在组件外部或作为独立包使用它们时,情况就不那么简单了。例如,这可能是我们处理computed和watch副作用时需要做的事情。

3. effectScope()

effectScope函数用于创建一个新的副作用作用域。

一个effectScope实例能自动自动收集运行在运行在内部的同步函数的副作用(如计算属性和侦听器),

当作用域不再活跃时,所有捕获的副作用可以被一起停止。

类型定义

typescript
function effectScope(detached?: boolean): EffectScope

其中EffectScope是一个接口,包含两个方法:

  • run<T>(fn: () => T): T | undefined:在作用域内运行一个函数,如果作用域不活跃则返回undefined。
  • stop(): void:停止当前作用域内的所有副作用。

4. getCurrentScope()

getCurrentScope函数用于获取当前活跃的副作用作用域。如果有多个作用域,它返回最外层的活跃作用域。

类型定义

typescript
function getCurrentScope(): EffectScope | undefined

5. onScopeDispose()

onScopeDispose函数用于在当前活跃的副作用作用域上注册一个处理回调函数。当相关的副作用作用域停止时,这个回调函数会被调用。这可以作为可复用的组合式函数中onUnmounted的替代品,因为它不与组件耦合,因为每个Vue组件的setup()函数也是在一个副作用作用域中调用的。

  • 类型定义

    typescript
    function onScopeDispose(fn: () => void): void

这些API提供了一种更细粒度的方式来管理和追踪副作用,这对于复杂的响应式逻辑和优化性能非常有用。通过使用这些API,开发者可以更精确地控制何时开始和停止副作用,从而避免不必要的计算和更新。

vue3源码: 在这里插入图片描述

6. 场景举例

js
function useMouse() {
  const x = ref(0)
  const y = ref(0)

  function handler(e) {
    x.value = e.x
    y.value = e.y
  }

  window.addEventListener('mousemove', handler)

  onUnmounted(() => {
    window.removeEventListener('mousemove', handler)
  })

  return { x, y }
}

问题:如果useMouse()在多个组件中被调用,每个组件都会附加一个mousemove监听器,并创建自己的xy引用副本。

期望:我们应该能够通过在多个组件之间共享相同的监听器和引用来提高效率,但我们不能这样做,因为每个onUnmounted调用都与单个组件实例耦合。

如果我们可以替换onUnmountedonScopeDispose来实现这一点,也是有问题的,因为setup函数也是在effectScope内

Vue官方推荐写法 在这里插入图片描述

花海相伴