跳到主要内容

effect

在 Vue 3 的响应式系统中,effect 函数扮演着核心角色,用于封装那些应该自动重新执行以响应响应式状态变化的副作用。

这些副作用通常包括组件的渲染逻辑、计算属性或任何当响应式状态改变时需要自动执行的函数。

什么是 effect

在 Vue 3 中,当你使用 reactive 或 ref 创建响应式状态时,这些状态的变化需要某种方式来触发视图的更新或执行其他副作用。

effect 函数就是这个机制的实现——它接受一个函数作为参数,并自动执行这个函数,同时跟踪函数内部访问的所有响应式状态。当这些状态变化时,effect 保证这个函数会被重新执行。

effect 的核心特性

  • 自动依赖收集:effect 在首次执行传入的函数时,自动跟踪并收集函数内部访问的所有响应式状态作为其依赖。
  • 响应式状态变化时的自动重新执行:一旦任何依赖的响应式状态发生变化,effect 确保这个函数会被再次执行,从而响应这些变化。
  • 细粒度的更新:通过精确跟踪函数内部访问的响应式状态,Vue 能够实现细粒度的更新,仅当实际依赖的状态变化时才重新执行函数,提高应用性能。

流程图

创建响应式数据
|
v
封装副作用
|
v
依赖收集(Track)
|
属性被修改
|
v
触发更新(Trigger)
|
v
副作用重新执行 ----> 重新依赖收集(如果有新的依赖)

  1. 创建响应式数据:通过 reactive 或 ref 函数创建响应式对象。
  • reactive({ count: 0 })
  1. 封装副作用:使用 effect 函数封装需要自动响应状态变化的副作用函数。
  • effect(() => console.log(state.count))
  1. 依赖收集(Track):当副作用函数首次执行时,访问响应式对象的属性会触发依赖收集。
  • 在 reactive 或 ref 的 get 操作中调用 track。
  • track 函数记录当前活动的副作用函数(即当前执行的 effect 函数)依赖于哪些响应式数据的哪些属性。
  1. 触发更新(Trigger):当响应式对象的属性被修改时,会触发更新。
  • 在 reactive 或 ref 的 set 操作中调用 trigger。
  • trigger 函数查找所有依赖于被修改属性的副作用函数,并重新执行它们。
  1. 副作用重新执行:effect 中封装的副作用函数重新执行,如果其中再次访问了响应式数据,则依赖关系会被重新收集。

为什么 Vue 3 设计使用 effect

  • 解决隐式依赖问题:在 Vue 2 中,组件的更新依赖于声明式的数据绑定和观察者模式。虽然这种方式简单直观,但在复杂应用中可能导致隐式的依赖和更新效率问题。通过 effect,Vue 3 的响应式系统能够更精确地追踪和管理状态变化与副作用之间的关系。

vue2:

<template>
<div>{{ message }}</div>
</template>

<script>
export default {
data() {
return {
message: "Hello, Vue 2!"
};
},
mounted() {
// 在这个 Vue 2 示例中,message 数据的更新将触发组件的重新渲染。虽然这
// 种模式易于理解,但在复杂应用中,组件的依赖关系可能变得难以追踪,尤其是
// 当数据流动涉及多个组件和嵌套时,可能导致不必要的重新渲染和性能问题。
setTimeout(() => {
this.message = "Updated message";
}, 2000);
}
};
</script>

vue3:

在 Vue 3 的示例中,我们使用了 Composition API 的 ref 来创建响应式数据,和 onMounted 生命周期钩子来处理副作用。Vue 3 的响应式系统内部使用 Proxy 来实现数据的响应式,并通过 effect 函数自动追踪响应式状态的使用和更新。这使得每个状态的变化和副作用之间的关系更加明确和可追踪,从而优化了更新效率和避免了不必要的渲染。

<template>
<div>{{ message }}</div>
</template>

<script setup>
import { ref, onMounted } from 'vue';

const message = ref("Hello, Vue 3!");

onMounted(() => {
setTimeout(() => {
message.value = "Updated message";
}, 2000);
});
</script>

  • 提高性能:effect 允许 Vue 3 实现更细粒度的更新策略。只有当组件实际使用的响应式状态变化时,组件才会更新。这减少了不必要的组件渲染,从而提高了应用的性能。
  • 简化 API:effect 为开发者提供了一个统一的 API 来处理副作用,无论是组件渲染、计算属性还是侦听器。这简化了 Vue 的使用,并使得代码更加一致和易于理解。
  • 更好的 TypeScript 集成:effect 和 Vue 3 的响应式 API 设计允许更好地利用 TypeScript 的类型推导和类型检查,提高了开发体验和代码质量。