watch

166 阅读1分钟

vue3 watch

watch API 与选项式 API this.$watch (以及相应的 watch 选项) 完全等效。watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用。默认情况下,它也是惰性的——即回调仅在侦听源发生变化时被调用。

  • 与 watchEffect 相比,watch 允许我们:

    • 惰性地执行副作用;
    • 更具体地说明应触发侦听器重新运行的状态;
    • 访问被侦听状态的先前值和当前值。

侦听单一源

侦听器数据源可以是一个具有返回值的 getter 函数,也可以直接是一个 ref

// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)

// 直接侦听一个 ref
const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})

侦听多个源

侦听器还可以使用数组以同时侦听多个源:

watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  /* ... */
})

与 watchEffect 相同的行为

watch 与 watchEffect 在手动停止侦听清除副作用 (将 onInvalidate 作为第三个参数传递给回调)、刷新时机调试方面有相同的行为。

类型声明:

// 侦听单一源
function watch<T>(
  source: WatcherSource<T>,
  callback: (
    value: T,
    oldValue: T,
    onInvalidate: InvalidateCbRegistrator
  ) => void,
  options?: WatchOptions
): StopHandle

// 侦听多个源
function watch<T extends WatcherSource<unknown>[]>(
  sources: T
  callback: (
    values: MapSources<T>,
    oldValues: MapSources<T>,
    onInvalidate: InvalidateCbRegistrator
  ) => void,
  options? : WatchOptions
): StopHandle

type WatcherSource<T> = Ref<T> | (() => T)

type MapSources<T> = {
  [K in keyof T]: T[K] extends WatcherSource<infer V> ? V : never
}

// 参见 `watchEffect` 共享选项的类型声明
interface WatchOptions extends WatchEffectOptions {
  immediate?: boolean // 默认:false
  deep?: boolean
}

vue2 watch

watch

  • 类型{ [key: string]: string | Function | Object | Array }

  • 详细

    一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个 property。

  • 示例

    var vm = new Vue({
      data: {
        a: 1,
        b: 2,
        c: 3,
        d: 4,
        e: {
          f: {
            g: 5
          }
        }
      },
      watch: {
        a: function (val, oldVal) {
          console.log('new: %s, old: %s', val, oldVal)
        },
        // 方法名
        b: 'someMethod',
        // 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
        c: {
          handler: function (val, oldVal) { /* ... */ },
          deep: true
        },
        // 该回调将会在侦听开始之后被立即调用
        d: {
          handler: 'someMethod',
          immediate: true
        },
        // 你可以传入回调数组,它们会被逐一调用
        e: [
          'handle1',
          function handle2 (val, oldVal) { /* ... */ },
          {
            handler: function handle3 (val, oldVal) { /* ... */ },
            /* ... */
          }
        ],
        // watch vm.e.f's value: {g: 5}
        'e.f': function (val, oldVal) { /* ... */ }
      }
    })
    vm.a = 2 // => new: 2, old: 1
    

    注意,不应该使用箭头函数来定义 watcher 函数 (例如 searchQuery: newValue => this.updateAutocomplete(newValue))。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.updateAutocomplete 将是 undefined。

  • 选项:deep

    为了发现对象内部值的变化,可以在选项参数中指定 deep: true。注意监听数组的变更不需要这么做。

    vm.$watch('someObject', callback, {
      deep: true
    })
    vm.someObject.nestedValue = 123
    // callback is fired
    
  • 选项:immediate

    在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调:

    vm.$watch('a', callback, {
      immediate: true
    })
    // 立即以 `a` 的当前值触发回调
    

    注意在带有 immediate 选项时,你不能在第一次回调时取消侦听给定的 property。