
watchEffect 是什么
watchEffect 接收一个函数,立即执行一次,依赖变化后重新执行。它不用写监听源:回调里读到哪个响应式数据,就追踪哪个。
收集依赖只发生在同步执行期间,读到哪个数据就追踪哪个。没读到的数据变化时,不会触发回调。
const message = ref('')const message2 = ref('')
watchEffect(() => { console.log(message2.value)})这段只读了 message2,所以 message2 变化时重跑,message 怎么变都不触发。
重新执行时依赖会重新收集:上一次读到、这一次没读到的数据,之后变化不会再触发回调。
清除副作用:onCleanup
回调的第一个参数是 onCleanup,它接收一个清理函数:
type OnCleanup = (cleanupFn: () => void) => void清理函数不在本次执行里运行,留到之后调用。时机有三个:下一次重新执行之前、手动停止监听之后、组件卸载时。
一次执行的过程是:先跑上一次注册的清理函数,再执行新的回调,再注册新的清理函数。
onCleanup 这个参数名从 Vue 3.2.31 开始使用。
用清理函数做防抖
输入框每变一次就发一次请求,连续输入会发出一串请求。没有清理的写法里,每次重跑都会新建一个定时器,之前的定时器不会被取消,连续输入就会发出多个请求。
把定时器交给 onCleanup,只保留最后一次:
const keyword = ref('')
watchEffect((onCleanup) => { const value = keyword.value
const timer = setTimeout(() => { console.log('发送请求', value) }, 500)
onCleanup(() => { clearTimeout(timer) })})输入停止 500 ms 后才发一次请求,这是 onCleanup 最常用的场景。
取消过期请求
新的请求发出后,上一个请求的结果已经没有用。清理函数里可以调用 AbortController.abort() 把它取消。
watchEffect(async (onCleanup) => { const controller = new AbortController()
onCleanup(() => { controller.abort() })
const res = await fetch(`/api/search?q=${keyword.value}`, { signal: controller.signal })})keyword.value 在 await 之前读到,依赖照常建立。请求被取消时 fetch 会抛 AbortError。
移除事件监听
每次重跑都挂一次监听,不清理就会挂上多个 handler。移除时要用同一个函数引用,所以把 handler 写成具名函数。
watchEffect((onCleanup) => { const text = keyword.value
function onScroll() { console.log(text) }
window.addEventListener('scroll', onScroll)
onCleanup(() => { window.removeEventListener('scroll', onScroll) })})停止与暂停监听
watchEffect 返回一个 WatchHandle,用它控制这次监听。停止之后,依赖再变化也不会重跑。
const handle = watchEffect(() => { console.log(message.value)})
handle.pause() // 暂停:依赖变化不再触发handle.resume() // 恢复handle.stop() // 停止:不能再恢复WatchHandle 本身可以直接调用,等同于 stop(),所以 const stop = watchEffect(fn) 之后调用 stop() 的旧写法依然有效。
flush 执行时机
flush 决定回调在哪个阶段执行,三个可选值,默认是 pre。
| flush | 执行时机 |
|---|---|
pre | 默认值,组件更新前执行 |
post | 组件更新后执行,DOM 已更新 |
sync | 依赖一变就同步执行 |
需要读写更新后的 DOM 时用 post:
watchEffect(() => { // 这里能拿到更新后的 DOM}, { flush: 'post' })onTrigger 与 onTrack
这两个选项只在开发模式下生效,用来观察依赖什么时候被读取、什么时候触发重跑。
watchEffect(() => { console.log(message.value)}, { onTrack(event) { console.log('追踪到依赖', event) }, onTrigger(event) { console.log('触发重跑', event) }})Vue 3 学习笔记
连载中分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 214 天
部分内容可能已过时