前言
使用过 Vue 的小伙伴,不管时 Vue2 还是 Vue3,我相信你都用过 Vue 中的监听器。监听器的作用就和它的名字一样:用来监听某个东西是否发生变化!我们很多需求都会用到监听器 watch,但是 Vue2 和 Vue3 中的监听器的用法有些许不一样,这就让一些从 Vue2 转 Vue3 的小伙伴不太适应,所以,我们今天就来好好学一学 Vue3 中的监听器如何使用!
1. watch
watch 是 Vue 3 中用来监听特定数据源的变化(例如 ref、reactive 或计算属性)的 API。当被监听的数据源发生变化时,会触发回调函数。watch 是一种 “显式” 的方式,只有当你指定了明确的监视目标时,才会触发。
用法:
javascript
复制代码
import { ref, watch } from 'vue';
const count = ref(0);
// 监听 `count` 的变化
watch(count, (newValue, oldValue) => {
console.log('count changed:', newValue, oldValue);
});
特点:
-
需要显式指定目标:你需要显式地提供要监听的响应式数据源(如
ref或reactive)和回调函数。 -
支持旧值:
watch的回调函数可以访问数据的旧值和新值,这使得它适用于需要对比前后状态的场景。 -
深度监听:
watch支持通过deep选项进行深度监听,适用于对象或数组的嵌套数据。javascript 复制代码 const user = reactive({ name: 'John', age: 30 }); watch(user, (newValue, oldValue) => { console.log('User changed:', newValue, oldValue); }, { deep: true }); -
监听计算属性或 getter:
watch可以用来监听计算属性或 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. 总结对比
| 特性 | watch | watchEffect |
|---|---|---|
| 依赖声明 | 需要显式声明依赖(例如 ref 或 reactive) | 自动追踪在副作用函数中使用的响应式数据 |
| 执行时机 | 依赖变化时执行,默认异步 | 立即执行并且在依赖变化时重新执行 |
| 返回值 | 提供新值和旧值 | 不提供新值和旧值,仅执行副作用 |
| 深度监听 | 支持深度监听(使用 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… 作者:小猪课堂