【vue3 Api - watchEffect 的讲解 & 使用】- 侦听响应式数据执行副作用(effect)函数
在了解 `watchEffect` api之前,需要了解在vue中,副作用函数的定义是什么!watchEffect f立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。注意,响应式数据必须要触发get才能劫持为依赖。watchEffect 有2个可传参数 ,并且有返回一个StopHandle函数用来停止侦听。1、第一个参数:(必传)effect 函数,收集依赖,并且立即
在了解 `watchEffect` api之前,需要了解在vue中,副作用函数的定义是什么:
字面意义的讲,副作用函数指的是会产生副作用的函数,例如下面该函数:
var num = 10 function effect(){ // 这里只是拿这两个当下例子,讲解的是思想!!并不是什么针对固定的对象。 document.body.innerText = 'hello vue3'; num *= 6 } function fn2(){ num = 20 // ... }
函数 effect 可以设置body和变量num的内容,但任何其他函数都可以读取、设置这些目标,也就是说,effect 函数的执行会直接或间接影响其他函数的执行,这时候就可以理解为effect函数产生了副作用。【案例和简要的说明来自(vue.js 设计与实现)该书】
在vue的底层设计中,effect 函数的运用概念挺多的。像vue的响应式设计就蕴含着该概念。
# watchEffect
为了根据响应式状态自动应用 和 重新应用 副作用,我们可以使用 watchEffect 函数。它立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。
传入的函数就是一个 effect函数 ,它会根据侦听的响应式数据的变化执行该函数。
- 立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。
注意,响应式数据必须要触发get才能劫持对应的内容为该副作用函数的依赖。
- watchEffect 接收2个参数 ,并且有返回一个
StopHandle
函数用来停止侦听。- 1、第一个参数:(必传)
effect 函数,收集依赖,并且组件初始化时立即执行一次;
并且 effect 函数可以接受一个 onInvalidate 函数参数,该参数执行并传入一个 callback ,每次监听回调执行前都会执行该 callback。 - 2、第二个参数对象(非必传): flush 、 onTrack 、 onTrigger;
flush 跟 watch() $watch() watch:{} 的flush 完全一致。同理也具备 <缓冲回调>
onTrack 、 onTrigger 看代码写的注释讲解!- 关于 `flush` 请查看我其他watch的文章,watch使用方法上讲的很细,
这么好竟然没人看?
- 关于 `flush` 请查看我其他watch的文章,watch使用方法上讲的很细,
- 1、第一个参数:(必传)
<script lang='ts' setup>
import { watchEffect,ref,computed } from 'vue';
let count = ref(0)
let Cc = computed(()=> count.value * 2)
let obj = reactive({
data:123,
inObj:{d1:0}
})
const stop = watchEffect((onInvalidate) => {
//! 立即执行传入的回调函数,同时响应式追踪其所有依赖,并在依赖变更时重新运行该回调函数。
console.log(Cc.value); // 注意,如果依赖是 ref 和 computed 对象,必须要.value,否则并不会视为依赖
console.log(count.value);
console.log(obj.data); // 同理,reactive数据也只会侦听触发了get的property(属性)
//! 注意首次执行并不会执行onInvalidate ,第二次开始才会!
onInvalidate(()=>{
//! 在回调触发前会调用该函数,并且stop()停止侦听的时候也会触发一次!
console.log('watchEffect的onInvalidate');
})
},{
flush:'pre', // flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
//! 跟踪之前会触发该函数,收集了多少个依赖就触发多少次!返回对应依赖信息
onTrack(e){console.log(e.target,'onTrack触发')},
//! 跟他名字一样依赖更改就触发执行,而且是同步的!没有所谓的缓冲回调
onTrigger(e){console.log(e.target,'onTrigger触发')}
})
setTimeout(() => {
stop() // 停止侦听 则调用该返回值即可
}, 1000*5);
</script>
# 停止侦听
const stop = watchEffect(() => {
console.log(obj.data);
})
setTimeout(() => {
stop() // 停止侦听 则调用该返回值即可
}, 1000*5);
# 清除副作用
在上面的代码中,你细心的话会注意到副作用函数有 `onInvalidate` 这么个函数参数!
有时副作用函数内会执行一些异步的函数,这些异步响应需要在其失效时清除 (即完成之前状态已改变了) 。所以侦听副作用传入的函数可以接收一个 onInvalidate
函数作入参,用来注册清理失效时的回调。当以下情况发生时,这个失效回调会被触发:
- 副作用即将重新执行时
- 侦听器被停止 (如果在
setup()
或生命周期钩子函数中使用了watchEffect
,在组件卸载时会自动停止侦听。)
例子1:
当 id 数据变更时,导致 token 失效,则调用注销token的方法。(这只是个例子,请融会贯通,举一反三!谢谢)
watchEffect(onCleanup => { const token = performAsyncOperation(id.value) onCleanup(() => { // id has changed or watcher is stopped. // invalidate previously pending async operation token.cancel() }) })
例子2: 这个例子讲解会更清晰点。。
我们之所以是通过传入一个函数去注册某个功能的失效回调,而不是从回调返回它,是因为返回值对于异步错误处理很重要。
在执行数据请求时,副作用函数往往是一个异步函数:
当id的值变化快,频繁http请求时,若前面的请求未完成,则会造成重复请求,则可以使用副作用函数的onCleanup参数,取消之前的http请求。
(叫啥都行,不过统一下较好,onCleanup是vue3最新版英文官网的名字定义)watchEffect(async (onCleanup) => { // 返回http请求方法和取消方法(清理函数) const { response, cancel } = doAsyncHttpWork(id.value) onCleanup(cancel) // 注册 取消方法(清理函数) data.value = await response // 请求数据 })
# watchPostEffect watchSyncEffect 就不讲了,不懂说明你根本不懂flush参数的作用,请移步我watch的文章。
watchSyncEffect 为例,简单讲就是除了 flush 参数固定为 'sync' ,其他所有功能跟 watchEffect 一样。
watchPostEffect
v3.2+
watchEffect
的别名,固定flush: 'post'
选项。
watchSyncEffect
v3.2+
watchEffect
的别名,固定flush: 'sync'
选项。
QQ交流群:522976012 ,欢迎来玩。
聚焦vue3,但不限于vue,任何前端问题,究其本质,值得讨论,研究与学习。
更多推荐
所有评论(0)