Vue3中watch到底怎么用?避坑指南+全场景实例
最近上手Vue3项目的前端小伙伴,好多都会来问:组合式API里的watch好像和之前Vue2的不太一样?一会儿要传ref一会儿传reactive的响应式数据,深度监听要不要加,什么时候用immediate?别急,今天咱们就用一问一答的方式,把Vue3 watch从基础到进阶聊透,配的都是你做项目真能用上的场景,看完就能直接上手写。
先搞懂Vue3 watch的核心参数
在聊具体用法前,咱们得把watch最常用的几个核心参数捋顺,不然看例子会有点懵,Vue3的watch和watchEffect不一样,它是惰性监听——也就是默认只有监听的数据变化了才执行回调,不像watchEffect初始化就跑一次,而且watch能精准追踪你需要监听的具体数据变化,不是瞎监听所有用到的,它的基本结构是:
import { watch, ref, reactive } from 'vue'
watch(
要监听的数据源,
回调函数(新值, 旧值) {
// 这里写数据变化后的逻辑
},
配置选项对象(可选)
)
其中配置选项里,最常用到的就是deep(深度监听)和immediate(立即执行),还有一个后面会提的flush(刷新时机),这俩配置是最容易踩坑的,咱们后面结合例子讲。
Vue2的watch和Vue3的watch有啥核心区别?
很多人一开始转组合式API,都是抱着Vue2的watch用法来套的,结果要么报错要么没效果,所以先区分一下核心差异很重要。
- 数据源的写法不同:Vue2的watch直接写在watch选项里,监听的是组件的data、props或者computed属性;Vue3的watch可以监听多个类型的数据源,包括单个ref、ref数组、reactive对象的某个属性(要用函数返回值)、整个reactive对象、甚至是getter函数。
- 深度监听的触发场景不同:Vue2里如果监听的是整个对象,默认不会监听内部属性变化,必须加deep: true;但Vue3里如果监听的是整个reactive对象,默认就是深度监听,不管你加不加deep,内部属性一变回调都会跑,而且这时候旧值和新值是同一个对象引用,没法做新旧值的比较,这点超级坑,后面咱们会单独拿出来说。
- 组合式API的灵活性更高:Vue3的watch可以写在setup()或者
``` 这时候两种方式都能实现自动滚动到顶部的效果,flush: 'post'的方式更简洁一点,不用额外写nextTick。
搜索商品
正在搜索...
- {{ item.title }} - ¥{{ item.price }}
暂无搜索结果
watch和watchEffect怎么选?
很多小伙伴又会问了,既然有watch还有watchEffect,到底什么时候用哪个? 简单总结一下:
- 如果你知道自己要精准监听哪个数据的变化,就用watch:比如监听输入框的内容、监听搜索条件、监听某个属性的变化,而且需要获取新旧值的时候,必须用watch。
- 如果你不知道自己要监听哪个数据,只知道回调里用到的所有数据变化了都要跑,就用watchEffect:比如监听回调里用到的多个ref、reactive属性,不需要获取新旧值,初始化就想跑一次的时候,用watchEffect更简洁。
举个watchEffect的例子:还是刚才的搜索功能,用watchEffect来写的话:
import { ref, watchEffect } from 'vue'
const keyword = ref('') const category = ref('全部') const searchResults = ref([]) const loading = ref(false)
const mockSearchAPI = (kw, cat) => { // 省略,和之前一样 }
// watchEffect初始化就会跑一次,而且自动追踪回调里用到的所有响应式数据 watchEffect(async (onCleanup) => { if (!keyword.value.trim()) { searchResults.value = [] return } const controller = new AbortController() const signal = controller.signal // 模拟搜索接口可以加个signal参数,用来取消上一次的请求 const res = await mockSearchAPI(keyword.value, category.value, signal) searchResults.value = res // onCleanup是watchEffect提供的清理函数,下一次watchEffect执行之前会先跑这个 onCleanup(() => { controller.abort() }) })
这里用了watchEffect的onCleanup函数,用来取消上一次未完成的搜索请求,这个功能是watch也有的,但watchEffect自动追踪数据变化,不用手动传数据源,更适合这种场景。 ## 总结一下Vue3 watch的避坑点 最后咱们再总结一下Vue3 watch最容易踩的坑,避免以后再犯: 1. **监听reactive对象的单个属性,必须用getter函数返回**。 2. **监听整个reactive对象,默认就是深度监听,新旧值是同一个引用**,如果要获取旧值,得用computed快照或者深拷贝。 3. **immediate: true的时候,第一次触发的旧值是undefined**。 4. **操作DOM的时候,记得用flush: 'post'或者nextTick**,确保DOM已经更新完成。 5. **同时监听多个数据源的时候,回调的参数是新值数组和旧值数组,顺序和数据源数组一致**。 好了,今天关于Vue3 watch的全场景实例和避坑指南就聊到这里了,希望对你有所帮助,如果你还有其他关于Vue3的问题,欢迎在评论区留言哦!版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网


