一文搞懂Vue3中watch和watchEffect区别和用法!

752 阅读5分钟

前言

使用过 Vue 的小伙伴,不管时 Vue2 还是 Vue3,我相信你都用过 Vue 中的监听器。监听器的作用就和它的名字一样:用来监听某个东西是否发生变化!我们很多需求都会用到监听器 watch,但是 Vue2Vue3 中的监听器的用法有些许不一样,这就让一些从 Vue2Vue3 的小伙伴不太适应,所以,我们今天就来好好学一学 Vue3 中的监听器如何使用!

1. watch

watch 是 Vue 3 中用来监听特定数据源的变化(例如 refreactive 或计算属性)的 API。当被监听的数据源发生变化时,会触发回调函数。watch 是一种 “显式” 的方式,只有当你指定了明确的监视目标时,才会触发。

用法:

javascript
复制代码
import { ref, watch } from 'vue';

const count = ref(0);

// 监听 `count` 的变化
watch(count, (newValue, oldValue) => {
  console.log('count changed:', newValue, oldValue);
});

特点:

  • 需要显式指定目标:你需要显式地提供要监听的响应式数据源(如 refreactive)和回调函数。

  • 支持旧值watch 的回调函数可以访问数据的旧值新值,这使得它适用于需要对比前后状态的场景。

  • 深度监听watch 支持通过 deep 选项进行深度监听,适用于对象或数组的嵌套数据。

    javascript
    复制代码
    const user = reactive({ name: 'John', age: 30 });
    
    watch(user, (newValue, oldValue) => {
      console.log('User changed:', newValue, oldValue);
    }, { deep: true });
    
  • 监听计算属性或 getterwatch 可以用来监听计算属性或 getter 的变化。

    javascript
    复制代码
    const doubled = computed(() => count.value * 2);
    
    watch(doubled, (newVal, oldVal) => {
      console.log('Doubled value changed:', newVal);
    });
    
  • 延迟执行:默认情况下,watch 在响应式数据源发生变化时异步触发回调,可以通过 immediate: true 让它在创建时立即执行一次回调。

    javascript
    复制代码
    watch(count, (newValue, oldValue) => {
      console.log('Count changed:', newValue, oldValue);
    }, { immediate: true });
    

使用场景:

  • 监听特定的变化:当你需要监听某个数据源的变化并在变化时执行某个副作用。
  • 旧值和新值对比:当你需要在数据变化时访问前后的值。
  • 深度监听:当你需要监听嵌套的对象或数组。

2. watchEffect

watchEffect 是一种更加自动化的方式,适用于你希望自动响应 当前作用域中的所有响应式数据变化。它会自动追踪所访问的响应式数据,并在这些数据变化时重新执行函数。

用法:

javascript
复制代码
import { ref, watchEffect } from 'vue';

const count = ref(0);

// watchEffect 会自动追踪 count 的变化
watchEffect(() => {
  console.log('count changed:', count.value);
});

特点:

  • 自动追踪依赖watchEffect 不需要显式指定要监听的响应式数据源,它会自动追踪在函数内访问的所有响应式数据,随这些数据变化而自动执行。
  • 不需要旧值和新值watchEffect 不提供旧值和新值,它只是重新执行整个副作用函数。
  • 立即执行watchEffect 默认在创建时立即执行一次回调,不需要像 watch 那样配置 immediate: true

使用场景:

  • 无需手动指定依赖:当你想要自动监听当前作用域内所有响应式数据的变化,而无需显式声明依赖。
  • 副作用与数据紧密结合:当副作用函数依赖于多个响应式数据时,watchEffect 可以自动侦测这些数据的变化并重新执行。
  • 无须获取旧值和新值:当你只关心副作用的重新执行,而不需要了解数据变化前后的具体值。

3. 总结对比

特性watchwatchEffect
依赖声明需要显式声明依赖(例如 refreactive自动追踪在副作用函数中使用的响应式数据
执行时机依赖变化时执行,默认异步立即执行并且在依赖变化时重新执行
返回值提供新值和旧值不提供新值和旧值,仅执行副作用
深度监听支持深度监听(使用 deep 选项)不支持深度监听
使用场景监听特定数据源的变化,比较前后值自动响应当前作用域内所有响应式数据的变化
副作用函数只在目标数据变化时执行副作用自动追踪并在任意数据变化时重新执行副作用

4. 适用场景的选择

  • 使用 watch 时:当你明确知道哪些数据需要被监听,并且需要对比数据的旧值和新值,或者需要深度监听复杂的数据结构时,watch 是一个合适的选择。
  • 使用 watchEffect 时:当你希望自动响应当前作用域内的数据变化,并且不关心旧值和新值时,watchEffect 更加方便且简洁。

5.手动停止监听器

通常来说,我们的一个组件被销毁或者卸载后,监听器也会跟着被停止,并不需要我们手动去关闭监听器。但是总是有一些特殊情况,即使组件卸载了,但是监听器依然存在,这个时候其实式需要我们手动关闭它的,否则容易造成内存泄漏。

比如下面这中写法,我们就需要手动停止监听器:

xml
 代码解读
复制代码
<script setup>
import { watchEffect } from 'vue'
// 它会自动停止
watchEffect(() => {})
// ...这个则不会!
setTimeout(() => {
  watchEffect(() => {})
}, 100)
</script>

上段代码中我们采用异步的方式创建了一个监听器,这个时候监听器没有与当前组件绑定,所以即使组件销毁了,监听器依然存在。

关闭方法很简单,代码如下:

scss
 代码解读
复制代码
const unwatch = watchEffect(() => {})
// ...当该侦听器不再需要时
unwatch()

我们需要用一个变量接收监听器函数的返回值,其实就是返回的一个函数,然后我们调用该函数,即可关闭当前监听器。

总结来说,watch 更加灵活和可控,适用于需要显式监听特定响应式数据变化的场景;而 watchEffect 则是更简洁的方案,适用于当副作用依赖于多个响应式数据时,不必显式声明依赖关系的场景。

借鉴一部分文章,原链接:juejin.cn/post/710900… 作者:小猪课堂