「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
⏳前言
上一篇文章Vue3.0 | 快速上手Compisition API新特性(上)讲到了setup、reactive、ref等新特性......这篇文章将学习Vue3.0的生命周期、watch、computed做一个笔记。
⏰ Vue3生命周期
Vue3中的生命周期钩子函数被命名为了onXXX的形式,并且只能同步地(synchronously)在setup函数中执行。下面介绍几个常用的生命周期钩子函数:
Vue2和Vue3.0中生命周期的映射关系
-> usebeforeCreatesetup()-> usecreatedsetup()beforeMount->onBeforeMountmounted->onMountedbeforeUpdate->onBeforeUpdateupdated->onUpdatedbeforeUnmount->onBeforeUnmountunmounted->onUnmountederrorCaptured->onErrorCapturedrenderTracked->onRenderTrackedrenderTriggered->onRenderTriggeredactivated->onActivateddeactivated->onDeactivated
beforeCreate、created
在Vue3中,beforeCreate和created与setup几乎同时执行,因此在Vue3中setup代替了beforeCreate和created,也就是说它们如今都不需要额外声明,只需要将它们其中的代码都在setup中编写即可。
onMounted
在页面被加载完成时执行,这个时候组件实例已经挂载完成,通常在这个时候可以做一些依赖 DOM 的初始化操作,例如我们可以在登陆页面加载完成后自动聚焦登录框:
onMounted() {
if (this.loginForm.username === '') {
this.$refs.username.focus()
} else if (this.loginForm.password === '') {
this.$refs.password.focus()
}
}
onUnmounted
onBeforeUnmount在组件被卸载前执行,而onMount在组件被卸载完成时执行,通常在这个时候可以清理自身组件的一些方法、逻辑、递归销毁子组件,例如我们在组件被销毁时需要主动移除组件的事件监听器:
onMounted(() => {
document.addEventListener(‘click’,onMounts);
})
onUnmounted(() => {
document.removeEventListener(‘click’,onMounts);
})
onUpdated
在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用,如果需要监听特定数据的改变并执行某些逻辑,最好不要使用 onUpdated 钩子函数而使用computed 或 watch,因为任何数据的变化导致的组件更新都会执行 onUpdated 钩子函数。
注意: 不要在onUpdated钩子中做更新数据的操作,会导致无限套娃的...
export default {
name: "App",
setup() {
onUpdated(() => {
console.log('updated')
})
}
};
onRenderTrigger
在数据更新时执行,接收一个参数event,其中包含数据更新前的值oldValue和更新后的值newValue
🔍 监听器watch
Vue3官方文档指出vue3版本的watch与2.0版本watch的功能是相等的(exact equivalent)
watch函数接收两个参数,第一个参数为需要监听的数据,也可以直接是一个ref。
第二个参数是一个回调函数callback,它有两个参数:数据更改后的值newValue和oldValue ,只要监听对象发生改变,这个回调函数就会执行
watch(() => data.count, (count, preCount) => {
console.log('newValue', count);
console.log('oldValue', preCount);
})
监听多个对象
watchEffect
watchEffect接收传入的一个函数作为参数,并且会立即执行它,watchEffect会自动响应式追踪其依赖,并在其依赖变更时重新运行该函数。
export default {
name: "App",
setup() {
const count = ref(0)
setTimeout(() => {
count.value = 1
}, 2000)
watchEffect(() => {
console.log(count.value);
})
}
};
运行后可以看到watchEffect被立刻执行,打印出count的原始值0,过了2s后watchEffect再次执行并打印出count修改后的值1
当watchEffect在组件地setup函数或者是生命周期函数中调用,监听器watcher会自动连接到组件地生命周期,并且自动地在组件卸载时停止
watch和watchEffect的区别:
- 懒执行:watchEffect在传入回调时会立即执行,且在依赖发生变化时重新运行该函数,而watch的回调函数只有在监听对象发生改变时执行
- watch可以监听到数据修改前的值和修改后的值
- watchEffect自动收集依赖源,依赖源改变时自动执行自身,而watch必须显示指定(return)依赖源
小问题:watchEffect和onBeforeUpdate 谁先执行?
<script>
import { ref } from "@vue/reactivity";
import { onBeforeMount, onBeforeUpdate, onMounted, onUpdated, watch, watchEffect } from "vue";
export default {
name: "App",
setup() {
const count = ref(0)
console.log('setup');
watch(() => count.value, () => {
console.log('watch');
})
watchEffect(() => {
const a = count.value
console.log('watchEffect');
})
onMounted(() => {
console.log('onMounted');
})
onBeforeMount(() => {
console.log('before mount');
})
onBeforeUpdate(() => {
console.log('before updated');
})
onUpdated(() => {
console.log('updated');
})
setTimeout(() => {
count.value = 1
}, 2000)
return {
count
}
}
};
</script>
控制台打印顺序如下图:
可以看到,
watchEffect会比onBeforeCreate先执行,这是因为watchEffect的第二个参数默认为{ flush: 'pre' },我们可以在第二个参数中传入配置选项{ flush: 'post' },这样一来onBeforeUpdate会先于watchEffect执行,但注意:onUpdated始终会在watchEffct后执行
onInvalidate 消除副作用
首先我们需要搞清楚副作用effect、effect function和onInvalidate
有些函数会产生一些副作用effect(例如ajax请求,DOM操作,操作localStorage,setTimeOut...),它们可能需要在失效时被及时清除
它会在watchEffect即将要执行时,或是在watchEffect被停止时执行,原因是onInvalidate需要在副作用执行之前清除它。在state已经被改变后,effect function执行前。
那么onInvalidate要在effect之前执行呢?原因是在副作用中可能会有await关键字,如果onInvalidate在它之后执行的话,副作用先于它执行,那么清除器并没有起作用,也就是清除器需要先行一步把副作用清除掉---用于拦截副作用
📱 Computed
计算属性computed在vue2.0是options,到了vue3.0后变成了API
接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式ref对象。
watchEffect函数返回的是一个停止函数stop
const stop = watchEffect(() => {
console.log(count.value)
})
stop() // 停止监听
<template>
{{ sayHiToJay }}
</template>
export default {
name: "App",
setup() {
const greetings = 'hi '
const SayHiToJay = computed(() => greetings + 'Jay')
return {
SayHiToJay
};
}
};
或者,接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象。
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
结言
这篇文章用于记录Vue3.0的学习过程,如果偏差错误欢迎提出指正!🎁