vue3.5推出的新API onWatcherCleanup 要怎么使用?有哪些应用场景?一开始没想出了,后来看了各位大佬写的文章,想到了一种使用方式:防抖!
onWatcherCleanup 基础用法
我们先来试试 onWatcherCleanup 的基础用法,主要看看触发时机。
const person = reactive({
count: 0,
name: 'jyk'
})
watch(person, () => {
// 2、然后才会打印
console.log('watch -- person', person)
onWatcherCleanup(() => {
// 1、先打印
console.log('onWatcherCleanup -- person', person)
})
})
啥时候会打印?先打印谁?
- person 变化发生后
- 第一次变化:只触发 watch 的回调
- 非第一次:先触发 onWatcherCleanup 的回调,后触发 watch 的回调
- 卸载组件前
- 如果 person 没有变更,不会触发 onWatcherCleanup 的回调
- 如果 person 有变更,才会触发 onWatcherCleanup 的回调
小结一下:
- watch 监听的对象发生变更的时候,onWatcherCleanup 才被执行,回调才会生效;
- 然后在变更前或者组件卸载前,才会调用 onWatcherCleanup 的回调函数。
列表数据多重 watch 之避免重复加载数据
上次说了列表管理里面,会对查询条件、翻页的页号进行 watch,然后会触发重复申请数据,本来想用 暂停、恢复的方式去解决,但是经过测试发现似乎不行。
现在想想,可以使用 onWatcherCleanup 来解决。
防抖篇
// 模拟查询条件
const find = reactive({
count: 0,
name: 'jyk'
})
// 模拟翻页的页号
const pager = reactive({
pageIndex: 1,
size: 10
})
// 列表数据
const list = shallowRef([])
// 计时器,这个要在外面定义
let timer: any
// 加载数据 的方法
const loadData = async (flag: number) => {
timer = setTimeout(() => {
// 加载数据
console.log('加载数据:loadData')
// 模拟 加载数据 等待 20ms 被调用
axios.get('/api/xxx').then(res => {})
}, 20)
onWatcherCleanup(() => {
console.log('onWatcherCleanup 删除 定时器')
clearTimeout(timer)
})
}
// 监听 查询
watch(find, async () => {
console.log('watch -- find', find)
// 查询条件变更,页号设置为 1
pager.pageIndex = 1
await loadData(find.count * 10)
})
// 监听页号
watch(() => pager.pageIndex, async () => {
console.log('watch -- pager.pageIndex', pager)
await loadData(pager.pageIndex)
})
使用防抖的思路,使用定时器延期发送申请,如果等待时间内有新的申请,那么就取消上次的定时器。
timer 在外面定义,可以支持多个watch,如果在 loadData 内部定义,那么只支持当前的 watch,不支持其他的watch。
这样的话,不管有多少个 watch,在等待时间内,只会申请一次。
和常规防抖的区别
如果你对防抖代码熟悉的话,就会发现,在 loadData 里面直接取消定时器也是一样的。
let timer: any
const loadData = async (flag: number) => {
clearTimeout(timer)
timer = setTimeout(() => {
// 加载数据
console.log('加载数据:loadData')
// 模拟 加载数据 等待 20ms 被调用
axios.get('/api/xxx').then(res => {})
}, 20)
}
这个确实。如果硬要找区别的话,那么就是当组件卸载的时候也会取消定时器。
取消申请篇
axios也支持取消申请,那么如果要取消的话,如何实现呢?
其他代码都一样,改一下 loadData 即可:
const controller = new AbortController()
const loadData2 = async (flag: number) => {
onWatcherCleanup(() => {
// 取消申请
console.log('onWatcherCleanup 取消申请')
controller.abort()
})
// 加载数据
axios.get('/foo/bar', {
signal: controller.signal
}).then((response: any) => {
//...
})
}
防抖还是取消?
我个人倾向于防抖,毕竟能不折腾后端就不折腾后端。当然了,见仁见智。