effect 是 Vue 3 响应式系统的核心 API,它会立即执行一段函数,并在函数内部读取响应式数据时建立依赖关系;当这些响应式数据发生变化后,Vue 会自动重新执行对应的函数,从而实现视图更新、计算属性联动等功能。下面通过一个简化版源码,模拟 Vue 3 中 effect、reactive、依赖收集和派发更新的基本实现。

一、使用效果

我们希望实现下面这样的功能:

        
const state = reactive({
  count: 0
})

effect(() => {
  console.log('count:', state.count)
})

state.count++
// 输出:
// count: 0
// count: 1
        
      

当 effect 函数中读取了 state.count,系统就会记录依赖。当 state.count 被修改时,再次执行这个 effect。


二、简化版源码

        
// 用于保存当前正在执行的副作用函数
let activeEffect = null

// WeakMap<Object, Map<PropertyKey, Set<ReactiveEffect>>>
const targetMap = new WeakMap()

/**
 * ReactiveEffect 类
 * Vue 内部会将 effect 封装成一个 ReactiveEffect 实例
 */
class ReactiveEffect {
  constructor(fn) {
    this.fn = fn

    // 当前 effect 依赖了哪些 Set
    // 用于后续清理依赖
    this.deps = []

    this.active = true
  }

  run() {
    if (!this.active) {
      return this.fn()
    }

    // 清除之前收集的依赖
    cleanupEffect(this)

    // 设置当前正在执行的 effect
    activeEffect = this

    // 执行用户传入的函数
    const result = this.fn()

    // 执行完成后清空 activeEffect
    activeEffect = null

    return result
  }

  stop() {
    if (this.active) {
      cleanupEffect(this)
      this.active = false
    }
  }
}

/**
 * 清理 effect 之前收集的