588 字
3 分钟
Vue 3 的 watch 侦听器

watch 做什么#

watch 监听响应式数据,数据变化时执行回调。它接收监听源、回调函数和配置项三个参数。

watch(
source, // ref、reactive 对象、getter 或数组
callback, // (newValue, oldValue, onCleanup) => {}
options, // { immediate, deep, onTrack, onTrigger }
)

immediate: true 让回调在创建时先执行一次。deep: true 让侦听器递归监听对象内部的变化。

监听单个 ref#

传入 ref 本身时,不加 deep 的 watch 只比较 message.value 是否被整体替换。要跟踪 nav.bar.name 这类嵌套属性,必须加 deep: true。

const message = ref({ nav: { bar: { name: '' } } })
watch(
message,
(newValue, oldValue) => {
console.log(newValue, oldValue)
},
{ immediate: true, deep: true },
)

同时监听多个 ref#

监听源写成数组,回调的 newValue 和 oldValue 也是数组,顺序与监听源一致。数组里任意一项变化都会触发。

const a = ref('')
const b = ref('')
watch([a, b], ([newA, newB], [oldA, oldB]) => {
// a 或 b 变化都会执行
})

监听 reactive 对象#

传入 reactive 对象会隐式创建深度侦听,加不加 deep: true 效果一样,任意层级的属性变化都会触发回调。

const state = reactive({ nav: { bar: { name: '' } } })
watch(state, (newValue, oldValue) => {
// nav.bar.name 变化也会触发
})

监听 reactive 的单个属性#

监听 reactive 的某个属性要传 getter 函数。直接写 state.name 不行,那是在求值,传进去的是一个普通字符串,watch 收不到任何依赖。

watch(
() => state.name,
(newValue, oldValue) => {
// 只有 state.name 变化才触发
},
)

用 getter 只追踪这一个属性,嵌套更深的路径写成 () => state.nav.bar.name 同样有效。

回调的清理函数#

回调的第三个参数是 onCleanup,完整签名是 (newValue, oldValue, onCleanup)。它在侦听器下一次执行回调之前运行,用来撤销上一次留下的副作用,比如定时器、事件监听和未完成的请求。

const keyword = ref('')
watch(keyword, (newValue, oldValue, onCleanup) => {
const timer = setTimeout(() => {
// 请求搜索结果
}, 300)
onCleanup(() => clearTimeout(timer))
})

只在开发环境生效的选项#

onTrack 在依赖被追踪时调用,onTrigger 在依赖触发变化时调用。

watch(source, callback, {
onTrack(e) {
console.log('track', e)
},
onTrigger(e) {
console.log('trigger', e)
},
})

第 8 篇,共 19 篇本文属于系列

Vue 3 的 watch 侦听器
https://www.choria.top/posts/vue3-watch/
作者
乔瑞雅·克林威尔
发布于
2026-04-08
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取

最后更新于 ,距今已过 214 天

部分内容可能已过时