【Vue3】利用watchEffect的清除副作用实现一个防抖函数
今天在Vue3官方文档上看了下 watchEffect 的介绍。以前用的时候都用得比较简单,所以以为这 api 也没啥值得特别掌握的地方,今天看了文档才发现,这个 api 并没有想象中那么简单~特别是看到清除副作用的时候比较懵逼,最后结合CSDN上一些大佬的博客解释才慢慢明白这其中的精髓。正好昨天刚写了一个关于Vue2如何实现防抖函数的文章,那么接下来,我就再次用一个防抖函数的实现过程来给大家分析
今天在Vue3官方文档上看了下 watchEffect 的介绍。以前用的时候都用得比较简单,所以以为这 api 也没啥值得特别掌握的地方,今天看了文档才发现,这个 api 并没有想象中那么简单~
特别是看到清除副作用的时候比较懵逼,最后结合CSDN上一些大佬的博客解释才慢慢明白这其中的精髓。
正好昨天刚写了一个关于Vue2如何实现防抖函数的文章,那么接下来,我就再次用一个防抖函数的实现过程来给大家分析一下这个api以及可能遇到的坑。
我模拟输入框搜索功能来演示,直接上代码:
<template>
<el-input
v-model="input"
placeholder="Please input"
/>
</template>
<script lang="ts" setup>
import { watchEffect, ref } from 'vue'
// 搜素关键字
const input = ref('')
// 定义一个 timer 来保存 setTimeout
let timer: any = null
// 定义一个返回 setTimeout 的方法
// ???(为什么要定义返回setTimeout的方法)
const getData = (wordKey: string) => {
return setTimeout(() => {
// ...Request Data
console.log(wordKey)
}, 3000)
}
// 开始监听 input 的 value 变化
// ???(如果把 getData 放在 watchEffect 之后,代码可以正常执行吗)
watchEffect(onInvalidate => {
timer = getData(input.value)
onInvalidate(() => {
if (timer) {
clearTimeout(timer)
}
})
})
</script>
在这段代码中,一共有两个问题,也就是我在写这段代码时遇到的两个坑需要给大家说明一下:
1.为什么要定义返回setTimeout的方法?
我之前写这个setTimeout的时候是这样写的:
const getData = (wordKey: string) => {
// ...Request Data
}
watchEffect(onInvalidate => {
timer = setTimeout(() => getData(input.value), 3000)
onInvalidate(() => {
if (timer) {
clearTimeout(timer)
}
})
})
这样写过后,我发现当 input 的 value 发生改变时,watchEffect
并不能监听到它的变化。我查阅了一些资料,找到一些线索,猜测 watchEffect
在收集依赖时,只会收集自身上下文作用域里的响应式数据。当然,这只是我的猜测,自己还没去证实过,之后会去源码中找线索继续求证~
总之,watchEffect是收集不到setTimeout内部函数的依赖的,所以,当时我将setTimeout提到了getData里,通过在watchEffect自身上下文作用域里将input.value传入到getData函数中来实现监听。如果各位大佬清除watchEffect收集依赖的方式,请在评论区或者私信中多多指教呀~
2.如果把 getData 放在 watchEffect 之后,代码可以正常执行吗?
我之前写这段代码的时候是这样写的:
watchEffect(onInvalidate => {
timer = getData(input.value)
onInvalidate(() => {
if (timer) {
clearTimeout(timer)
}
})
})
const getData = (wordKey: string) => {
return setTimeout(() => {
// ...Request Data
console.log(wordKey)
}, 3000)
}
大家可以看到,我把 getData 放到了 watchEffect 之后,运行后我发现报了这样一个错:
大家可以看到是一个空指针的报错。后来我发现了是 getData 找不到,why?我不是定义了吗,Vue bug?!
后来去仔细看了下官方文档发现这样一段话:
原来是立即执行函数,这好像跟Promise类似哈~
这样就能解释通了,在他执行的时候,我们的 getData 根本还没有注册到组件实例上,当然报空指针啦。
不过我在官方文档后面又看到了可以通过配置 flush 选项来控制watchEffect 内部监听函数的执行时机:
于是我试一下将代码这样改写:
<template>
<el-input
v-model="input"
placeholder="Please input"
/>
</template>
<script lang="ts" setup>
import { watchPostEffect, ref } from 'vue'
// 搜素关键字
const input = ref('')
// 定义一个 timer 来保存 setTimeout
let timer: any = null
// 开始监听 input 的 value 变化
watchPostEffect(onInvalidate => {
timer = getData(input.value)
onInvalidate(() => {
if (timer) {
clearTimeout(timer)
}
})
})
// 定义一个返回 setTimeout 的方法
const getData = (wordKey: string) => {
return setTimeout(() => {
// ...Request Data
console.log(wordKey)
}, 3000)
}
</script>
<style>
</style>
也就是利用 watchPostEffect 去改变内部监听函数的执行时机,发现一样可以实现咱们的需求~
更多推荐
所有评论(0)