返回

Vue.js 中 watch 函数的深入解析,掌握动态监听与响应式更新的精髓

前端

学习笔记:Vue 中的 watch 函数,何时使用(附源码解析)

在上一篇分享中,我们讨论了 computed 的一些使用方式和源码解析。突然想到,在日常开发中,很多开发者并不太清楚何时该用 computed,何时该用 watch。因此,本文决定来总结一下 watch 的用法和 watch 的源码解析。

1. watch 的基本用法

watch 函数允许您在数据变化时执行代码。其基本用法如下:

watch: {
  name: {
    handler(newVal, oldVal) {
      // `newVal` 是新值,`oldVal` 是旧值
      console.log(`姓名已从 ${oldVal} 变更至 ${newVal}`);
    },
    immediate: true // 立即执行一次
  }
}

在这个例子中,我们将监听 name 属性的变化。当 name 属性发生变化时,将触发 handler 函数。在 handler 函数中,我们可以访问新值(newVal)和旧值(oldVal),并根据需要执行相应的操作。

immediate 选项表示是否在组件首次渲染时立即执行一次 handler 函数。默认为 false,表示仅在数据发生变化时执行。

2. watch 的进阶用法

除了基本用法之外,watch 函数还支持一些进阶用法,包括:

  • 深度监听: 通过在属性前添加一个 period(.),您可以对对象的属性进行深度监听。例如:
watch: {
  'user.name': {
    handler(newVal, oldVal) {
      console.log(`姓名已从 ${oldVal} 变更至 ${newVal}`);
    }
  }
}

这将监听 user 对象的 name 属性的变化,无论 name 属性是直接更改还是通过子属性更改。

  • 函数语法: 除了使用对象语法之外,您还可以使用函数语法来定义 watch 函数。例如:
watch(function (newVal, oldVal) {
  console.log(`姓名已从 ${oldVal} 变更至 ${newVal}`);
})
  • 使用字符串作为属性名: 有时,您可能需要监听一个属性,但您不确定它的确切名称。在这种情况下,您可以使用字符串作为属性名。例如:
watch('name', function (newVal, oldVal) {
  console.log(`姓名已从 ${oldVal} 变更至 ${newVal}`);
})

3. watch 源码解析

为了更好地理解 watch 函数的内部运作机制,我们来看一下它的源码。在 Vue.js 的源码中,watch 函数被定义在 src/core/instance/state.js 文件中。

export function stateMixin (Vue) {
  // ... 省略其他代码

  Vue.prototype.$watch = function (expOrFn, cb, options) {
    var vm = this
    if (isPlainObject(cb)) {
      options = cb
      cb = cb.handler
    }
    var watcher = new Watcher(vm, expOrFn, cb, options)
    if (options && options.immediate) {
      cb.call(vm, watcher.value)
    }
    return function unwatchFn () {
      watcher.teardown()
    }
  }
}

从源码中可以看到,watch 函数首先创建一个 Watcher 实例,然后将这个 Watcher 实例添加到当前组件的 watcher 列表中。Watcher 实例包含了以下几个重要属性:

  • expOrFn: 要监听的表达式或函数。
  • cb: 当表达式或函数的值发生变化时要执行的回调函数。
  • options: 一些选项,包括 immediate、deep 等。

当表达式或函数的值发生变化时,Watcher 实例将触发回调函数。

4. 何时使用 watch

那么,我们什么时候应该使用 watch 函数呢?一般来说,我们应该在以下情况下使用 watch 函数:

  • 当您需要在数据发生变化时执行某些操作。
  • 当您需要监听对象的属性变化,而 computed 无法满足您的需求。
  • 当您需要监听数组的变化。

5. 何时不应使用 watch

在以下情况下,我们不应该使用 watch 函数:

  • 当您只需要在组件首次渲染时执行一次操作。
  • 当您只需要在组件销毁时执行一次操作。
  • 当您只需要在某些特定事件发生时执行操作。

在这些情况下,我们应该使用其他更适合的钩子函数或事件监听器。

6. 性能优化

过度使用 watch 函数可能会导致性能问题。因此,我们应该谨慎使用 watch 函数,并尽量避免在组件中使用过多的 watch 函数。

为了优化 watch 函数的性能,我们可以使用以下技巧:

  • 使用 computed 代替 watch: 如果您只需要在组件渲染时执行一次操作,或者您只需要监听数据的变化,而不需要执行任何操作,那么您可以使用 computed 代替 watch。
  • 使用函数语法定义 watch 函数: 函数语法定义的 watch 函数比对象语法定义的 watch 函数性能更好。
  • 使用深度监听时,尽量避免监听整个对象: 深度监听整个对象可能会导致性能问题。因此,我们应该尽量避免监听整个对象,而应该只监听我们真正需要监听的属性。

7. 总结

watch 函数是 Vue.js 中一个强大的工具,它允许您在数据变化时执行代码。通过理解 watch 函数的基本用法、进阶用法和源码解析,您可以更好地掌握 watch 函数的使用技巧。在使用 watch 函数时,您应该谨慎使用,并尽量避免过度使用 watch 函数,以优化组件的性能。