如何理解Vue中的effectscope?

sno*_*fox 7 javascript side-effects vuejs3

官方RFC

有一个例子effect

function createSharedComposable(composable) {
  let subscribers = 0
  let state, scope

  const dispose = () => {
    if (scope && --subscribers <= 0) {
      scope.stop()
      state = scope = null
    }
  }

  return (...args) => {
    subscribers++
    if (!state) {
      scope = effectScope(true)
      state = scope.run(() => composable(...args))
    }
    onScopeDispose(dispose)
    return state
  }
}
Run Code Online (Sandbox Code Playgroud)

useMouse我知道它会做什么,当我们使用API时,它会强制所有组件只计算一次

但我无法理解 的概念effect,以及它是如何工作的?

特别是一些 API,effect例如getCurrentScope. 我试图查看 的返回值getCurrentScope,但我一无所获。

请帮我!

Xin*_*hao 13

效果是反应式框架(VueJS 和 React)中使用的常用术语,指(我相信)副作用。如果您熟悉函数式编程,您可能已经知道它被称为副作用,因为它不是“纯函数”,因为它会改变共享或全局状态。

忽略学术术语,这些系统中的效果仅指任何执行定制操作的应用程序定义的方法,例如

const foo = () => {
  // I do something bespoke
}
Run Code Online (Sandbox Code Playgroud)

效果的含义确实如此广泛。您的方法在其主体中实际执行的操作对于框架来说并不重要。框架所知道的就是foo做一些非结构化的事情。VueJS 的额外作用是通过其反应性系统来监视您的效果是否依赖于任何反应性数据。如果是这样,每次它所依赖的数据发生变化时,VueJS 都会重新运行你的效果。

效果(或副作用)并不是什么坏的、特殊的或高级的东西。事实上,您的应用程序都是关于制作效果/副作用的。例如,VueJS 应用程序中最常见的效果是DOM 操作。它是如此常见,以至于 VueJS 将其提取为不同的抽象:template。在幕后,模板被编译为渲染函数(看起来很像上面的函数foo),每次一些依赖的反应数据发生变化时,这些函数都会被重新评估。这就是 VueJS 让你的 UI 保持最新的方式。

常见效果的另一个极端是那些真正定制的效果,例如,每当数据发生变化时,您只想执行一些老式命令式操作(例如 jQuery 样式)。而 VueJS 可以让你做到这一点watchEffect:你给 VueJS 一个 lambda,每次它的依赖项发生变化时,VueJS 都会盲目地调用它,而不询问它在做什么。

VueJS 通过运行您的效果来发现您对反应性数据的依赖。只要您的效果yourState.bar在执行期间访问任何反应性数据(例如),VueJS 就会注意到这一点并记录您的效果对yourState.bar

从本质上讲,反应性系统只是古老的可观察/订阅者模式的现代版本。反应状态是可观察的,效果是订阅者/观察者。如果你超越魔术层并以订阅者模式的形式考虑 VueJS,那么它无法避免一个问题:每当你有 时subscribe,你就必须处理unsubscribe,否则你将有内存或资源泄漏,仅仅因为你保留保留订阅者(他们反过来保留其他东西)并且没有任何东西可以被释放。这个取消订阅部分就是 RFC 所说的“ effect dispose ”。

通常,在处理取消订阅/处置/清理/取消业务时,您会遇到两个挑战:

  • 决定何时取消订阅/处置
  • 知道如何取消订阅/处置

在典型的反应式框架中,上述两者都是应用程序的责任。作为应用程序开发人员,您是唯一知道何时不再需要订阅以及如何反转您在创建订阅时进行的额外资源分配(如果有)的人。

但在典型的 VueJS 应用程序中,您很少需要手动处理任何类型的清理(停止 DOM 修补、监视或计算等)。这是因为 VueJS 会自动处理它。当组件被卸载时,在组件的设置方法中建立的反应效果将被自动处理(无论适当清理所需的是什么)。这是怎么发生的?假设 VueJS 内部还存在其他一些魔法,可以将所有效果与相应组件的生命周期相关联。从技术上讲,正如 RFC 所说,这种魔力就是effectScope.

从概念上讲,每个组件都会创建一个effectScope. 在组件设置方法中定义的所有效果都将与该范围相关联。当组件销毁时,VueJS 会自动销毁作用域,这将清理关联的效果。

RFC 提议制作effectScope一个公共 api,以便人们可以在不使用 VueJS 组件的情况下使用它。这是可能的,因为 Vue3 是通过模块化构建的。您可以使用 Vue 的反应性模块,而无需使用整个 VueJS。但如果没有底层的effectScope,您就必须手动处理所有效果。