[vue3] watch和watchEffect简记

发布时间 2023-11-01 17:50:29作者: feixianxing

watch的数据源

watch函数的第一个参数是监听的数据源,可以是:

  • ref和computed创建的响应式数据;
  • reactive创建的响应式对象;
  • getter函数;
  • 多个数据源组成的数组;

  • 响应式对象的属性需要使用getter监听。
  • 当数据源是响应式对象时,其属性的变更会触发回调函数,但是接收到的newValueoldValue是一样的,因为对象的引用是同一个。
  • 和上一条不同,如果数据源是一个“返回响应式对象”的getter,除非对象的引用变更,否则不会触发回调函数。可以使用deep监听其所有的属性,使用递归实现,开销大,谨慎使用。
  • 一般watch是先设置,监听到变化后再触发。如果需要设置的时候就先立即触发一次,使用immediate

watchEffect

特点

  • watchEffect不需要指定依赖,只需要传入回调函数,它会自动追踪函数内部依赖的响应式数据,并在这些数据发生变更时触发回调函数。
  • 对于有多个依赖项的监听器来说,不需要手动维护依赖列表,比watch方便很多。
  • watchEffect默认是immediate的,即立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
  • watchEffect只在同步执行期间追踪依赖,对于使用async await的异步回调函数,只有在第一个await之前访问的响应式数据会被追踪。

侦听器回调的触发时机

响应式状态的变更会同时触发:Vue组件更新侦听器回调

默认情况下,先执行侦听器回调,再执行Vue组件更新。这意味着在侦听器回调中的DOM是Vue更新组件之前的状态。

可以使用flush: post选项,调整这一顺序:

watch(source, callback, {
  flush: 'post'
})

watchEffect(callback, {
  flush: 'post'
})

如果觉得配置选项太麻烦,对于watchEffect,有一个便捷的替代品:watchPostEffect

import { watchPostEffect } from 'vue'

watchPostEffect(() => {
  /* 在 Vue 更新后执行 */
})

停止侦听器

同步创建的侦听器会绑定在宿主组件实例上,并会在组件卸载时自动停止。

当异步创建了一个侦听器时,它不会被绑定到组件上,为了防止内存泄漏,需要手动停止。

watch和watchEffect函数存在一个返回值,是一个用于停止侦听器的函数:

const unwatch = watchEffect(() => {})

// ...当该侦听器不再需要时
unwatch()

尽量不要使用异步创建侦听器,如果需要等待异步数据,可以使用条件式的侦听逻辑:

// 需要异步请求得到的数据
const data = ref(null)

watchEffect(() => {
  if (data.value) {
    // 数据加载后执行某些操作...
  }
})