Vue3 源码分析之Watch的实现

118 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情

Vue3 Watch 源码实现

在Vue3中,watch的实现方式有所不同,使用了新的API watchEffectwatch

下面我们来详细了解一下它们的实现原理。

watchEffect

watchEffect是一个立即执行的响应式副作用函数,用于执行响应式数据的副作用和响应式数据的收集。

每一次响应式数据的变化都会重新执行该函数。

watchEffect实际上是watch的特殊形式,只监听其所使用的响应式数据,不需要手动指定监听的响应式数据。

下面是watchEffect的核心实现代码:

function watchEffect(effect) {
  // 创建响应式副作用函数
  const runner = effect.bind(null, {
    get,
    run: effect
  })

  // 第一次执行副作用函数
  runner()

  // 收集响应式数据
  return () => {
    stop(runner)
  }
}

从上面的代码可以看出,watchEffect的实现分为两个步骤:

  1. 创建响应式副作用函数
  2. 收集响应式数据

其中,第一步是通过bind方法创建一个响应式副作用函数,并且将get方法和当前副作用函数绑定到一个对象上,以便在副作用函数内部可以使用get方法获取响应式数据。

第二步是在第一次执行副作用函数时,会自动收集该副作用函数内部所使用的响应式数据。当响应式数据发生变化时,会重新执行该副作用函数,并且重新收集响应式数据。

watch

watch是一个更加灵活的API,可以用于监听一个或多个响应式数据的变化,并在数据变化时执行相应的回调函数。

下面是watch的核心实现代码:

function watch(source, cb, options) {
  // 创建一个响应式的getter
  const getter = () => source()

  // 创建一个响应式副作用函数
  const runner = effect(getter, {
    lazy: true,
    ...options
  })

  // 执行回调函数
  let oldValue = undefined
  runner.onTrack = () => {
    oldValue = runner()
  }
  runner.onTrigger = () => {
    const newValue = runner()
    cb(newValue, oldValue)
    oldValue = newValue
  }

  // 手动执行一次副作用函数
  if (options && options.immediate) {
    cb(runner(), undefined)
  }

  // 返回一个停止侦听响应式数据的函数
  return () => {
    stop(runner)
  }
}

从上面的代码可以看出,watch的实现也分为两个步骤:

  1. 创建响应式副作用函数
  2. 执行回调函数

其中,第一步是通过创建一个响应式的getter来获取响应式数据,并且创建一个响应式副作用函数来收集响应式数据的变化。

第二步是在响应式数据发生变化时,执行回调函数,并将新旧值作为参数传入回调函数中。

总结

通过实现watchEffectwatch,我们可以更好的理解Vue3中响应式原理的实现方式。

watchEffect可以用于执行响应式数据的副作用和响应式数据的收集

watch可以用于监听响应式数据的变化并执行相应的回调函数。

Vue3的响应式原理更加高效和灵活,为开发者提供了更好的响应式编程体验。