【Vue.js】Composition API - watch() 和 watchEffect()

67 阅读3分钟

watchEffect()

概述:

  • 立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。(与 React 中的 useEffect 类似)
  • watchEffect 的第一个参数就是要运行的副作用函数。这个副作用函数的参数也是一个函数,用来注册清理回调。清理回调会在该副作用下一次执行前被调用,可以用来清理无效的副作用。
  • watchEffect 的第二个参数是一个可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖。
  • watchEffect 的返回值是一个用来停止该副作用的函数。
function watchEffect(
  effect: (onCleanup: OnCleanup) => void,
  options?: WatchEffectOptions
): StopHandle

type OnCleanup = (cleanupFn: () => void) => void

interface WatchEffectOptions {
  flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
  onTrack?: (event: DebuggerEvent) => void
  onTrigger?: (event: DebuggerEvent) => void
}

type StopHandle = () => void

watchEffect 的一些使用场景

  1. 副作用清除
  2. 停止侦听器
  3. 配置选项

watch()

概述:

侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。

代码示例:

function watch<T>(
  source: WatchSource<T>,
  callback: WatchCallback<T>,
  options?: WatchOptions
): StopHandle

// 侦听多个来源
function watch<T>(
  sources: WatchSource<T>[],
  callback: WatchCallback<T[]>,
  options?: WatchOptions
): StopHandle

type WatchCallback<T> = (
  value: T,
  oldValue: T,
  onCleanup: (cleanupFn: () => void) => void
) => void

type WatchSource<T> =
  | Ref<T> // ref
  | (() => T) // getter
  | T extends object
  ? T
  : never // 响应式对象

interface WatchOptions extends WatchEffectOptions {
  immediate?: boolean // 默认:false
  deep?: boolean // 默认:false
  flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
  onTrack?: (event: DebuggerEvent) => void
  onTrigger?: (event: DebuggerEvent) => void
}

语法:

第一个参数:

watch 的第一个参数是侦听器的源。这个来源可以是以下几种:

  • 一个函数,返回一个值
  • 一个 ref
  • 一个响应式对象
  • ...或是由以上类型的值组成的数组

第二个参数:

watch 的第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。

当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。

第三个参数:

watch 的第三个可选的参数是一个对象,支持以下这些选项:

  • immediate:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined
  • deep:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器。
  • flush:调整回调函数的刷新时机。参考回调的刷新时机及 watchEffect()
  • onTrack / onTrigger:调试侦听器的依赖。

特点:

  • watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。
  • 当使用 getter 函数作为源时,回调只在此函数的返回值变化时才会触发。如果你想让回调在深层级变更时也能触发,你需要使用{ deep: true }强制侦听器进入深层级模式。
  • watch的深层级模式时,如果回调函数由于深层级的变更而被触发,那么新值和旧值将是同一个对象。

watch 和 watchEffect 的对比

  • watch 可以懒执行副作用
  • watch 更加明确是应该由哪个状态触发侦听器重新执行 ([], xxx)
  • 可以访问所侦听状态的前一个值和当前值。