一、前言
大家好,我是地霊殿__三無,兜兜转转,总算略有空闲,可以静下来学习学习vue3的相关知识了,今天整点hook函数,在学习之余记录一下,加深印象。
二、生命周期
vue3和vue2的生命周期基本相同,不一样的地方在于vue3用setup代替了beforeCreate和created。
且vue3的生命周期都是按需加载的,且是在原有的命名基础前增加on,setup除外。
| vue2 | vue3 |
|---|---|
beforeCreate | setup |
created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
errorCaptured | onErrorCaptured |
renderTracked | onRenderTracked |
renderTriggered | onRenderTriggered |
整体的生命周期还是可以沿用vue2.x的思想的,将beforeCreate和created修改为setup即可。
写法也与vue2.x有所不同,需要引入。
在setup函数或者setup标签里填写,下面用setup标签的写法。
<script setup lang="ts">
import { onBeforeMount, onMounted } from 'vue'
onBeforeMount(() => {
console.log('------onBeforeMount', 1)
})
onMounted(() => {
console.log('------onMounted', 2)
})
</script>
三、监听函数
1、watch
惰性监听,作用和vue2.x提供的this.$watch相同。
vue3的watch监听的对象得是响应式的对象,即reactive或者ref定义的变量。
监听单一源
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
)
// 直接侦听一个ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
数组形式监听多个源,试了一下,好像没发现监听前的值,几个都是修改后的值了。
const state = reactive({ count: 0 })
const state2 = reactive({ count: 3 })
watch([state, state2], ([stateNow, state2Now], [prevState, prevState2]) => {
console.log('改变后的值', stateNow, state2Now)
console.log('改变后的值', prevState, prevState2)
console.log('监听对象', state, state2)
})
2、watcheffect
为什么有了watch,还需要有watcheffect呢,因为watch是惰性的,watch监听一个或者多个 特定 的响应性属性,仅当这些依赖项更改时才会触发,而且需要immediate为true,才会在组件创建后开始监听;而watchEffect是监听函数里的 任何 依赖项,默认就是在创建组件之后就开始监听,当监听函数里的任何依赖项发生更改时,就会触发。
watcheffect注重的是过程!!!
2.1 常规使用
我们想监听下state的count值,顺便看一下几个监听函数(在上一小节已经写了)的触发顺序。
import { onBeforeMount, onMounted, reactive, watch, watchEffect } from 'vue'
watchEffect(() => {
console.log('顺序2', 'watchEffect监听', state.count)
})
可以看到,watch监听单个源的,触发的最快,其次是watchEffect,最后才是watch监听多个源。
2.2 在watcheffect中使用异步函数会来副作用,如何应对
在watchEffect里使用异步函数,经常会发生以下的场景:
监听的依赖项发生变化了,watchEffect被触发,然后调用了异步函数,结果异步函数还没触发,依赖项又变化了,那异步函数又被执行了一次,就结果而言,我们应该是只需要最新的那次就可以了,结果这里白白浪费了一次异步函数的执行资源。
这就需要我们的onInvalidate参数了。
onInvalidate 执行时间:
- 副作用即将重新执行时(监听对象改变时)
- 侦听器被停止 (如果在 setup() 或生命周期钩子函数中使用了 watchEffect,则在组件卸载时)
首先我们利用定时器创建一个异步函数change
let timer: NodeJS.Timeout|undefined
const change = async (Num: number) => {
timer = await setTimeout(() => {
console.log(Num)
}, 1000)
}
然后完善一下我们的watchEffect函数,添加一个onInvalidate,执行时机写在上面了,我们可以在onInvalidate函数内,去判断异步函数执行没,没执行,就手动取消上一次的定时器,这样只会执行最后一次的定时器。
watchEffect(onInvalidate => {
console.log('顺序2', 'watchEffect监听', state.count)
const tmp = change(state.count)
onInvalidate(() => {
console.log('执行了onInvalidate')
if(timer) {
clearTimeout(timer)
}
})
})
2.3 watchEffect的第二个参数---极少用到
副作用刷新时机 flush 一般使用post
| pre | sync | post | |
|---|---|---|---|
| 更新时机 | 组件更新前执行 | 强制效果始终同步触发 | 组件更新后执行 |
写法如下:
watchEffect(onInvalidate => {
console.log('顺序2', 'watchEffect监听', state.count)
const tmp = change(state.count)
console.log(tmp)
onInvalidate(() => {
// tmp.cancel()
console.log('执行了onInvalidate')
if(timer) {
clearTimeout(timer)
}
})
}, {
flush: 'post',
onTrigger () {
console.log('触发ontrigger')
}
})
即使是post,onTrigger的触发时间也是最前的,之后是onInvalidate,才到watchEffect的监听逻辑
2.4 如何手动停止调用
比如我们监听对象的值大于10之后,我们就不打算监听了,那就得手动调用一次
写法如下
change函数里添加逻辑,大于10就调用stop
const change = async (Num: number) => {
timer = await setTimeout(() => {
console.log(Num)
if(Num > 10) {
console.log('调用stop函数')
stop()
}
}, 1000)
}
stop函数就是我们的watchEffect
const stop = watchEffect(onInvalidate => {
和上述的函数内容一致,就不重复混字数了
)
调用之后,watchEffect就失效了,不会再监听了(组件销毁时,也是这种逻辑,不过是自动调用而已)
3、computed
computed我们是相当熟悉了,就简单过一下。
ref和computed在import之后,我们用一段代码来讲讲触发过程。
demoCount就是我们的计算值,它的值是count变量的值+10,一开始,当settimeout运行后,对demoCount进行赋值操作,这并不能直接修改demoCount的值,而是会触发set方法,此时的count = 100 - 30 = 70,然后是触发get方法,返回了80 (=70+10)这一结果。
const count = ref(0)
const demoCount = computed({
get: () => {
return count.value + 10
},
set: (param) => {
count.value = param - 30
}
})
setTimeout(() => {
demoCount.value = 100
})
四、小结
本次对vue3的生命周期和各类监听api进行了一次小结,我个人觉得,用的多的还是watch,其次是computed,最后是watchEffect。不过多了解一些总归是没毛病的。
ps: 我是地霊殿__三無,最近没状态,兜兜转转才水出一篇。