🎈Vue3带来了Composition API
,在这其中,Hooks是其重要组成部分,本文将深入探讨Vue3中Hooks,帮助你在Vue3开发中更加得心应手。
什么是Hook函数
Hook
翻译过来是钩子的意思,其本质上是一组可复用的函数。简单理解来说,你能够在不同的组件中,实现相同的代码逻辑,以达到代码复用、提高维护性的效果。那为何叫'钩子'呢,我的理解是:
它可以通过特定的函数将逻辑 "钩入" 组件中,使得开发者能够更灵活地构建和管理组件的功能从而提高代码的可读性以及可维护性等
细则:
🐼看完上面的概念,可能还是一头浆糊,这不就是普普通通封装了一个函数然后给我们调用嘛,跟我们平时的函数有啥区别?是,这也是我在学习过程中很疑惑的点,来看看下面的解释吧!
🐼在开发过程中,我们经常会发现一些可重复利用的代码块,于是我们将其封装成函数以供调用。这类函数包括工具函数,但又不止工具函数,因为我们可能也会封装一些重复的业务逻辑。但在以往,在前端原生开发中,我们所封装的函数,大多数是"无状态"的,不能够建立数据与视图之间的联系。
🐼那何为"有状态"的函数呢?这里的"有状态",实际上是指是否含有响应式变量 。我们知道,基于MVC
架构的React
框架和基于MVVM
的Vue
框架都引入了"状态"这一概念。状态是特殊的JavaScript
变量,它的变化能够引起视图的变化。在这类框架中,如果一个变量的变化不会引起视图变化,则为普通变量,如果一个变量已经被框架注册为状态,那么这个变量的变化就会引起视图变化,我们称之为响应式变量。
总结即:如果一个函数包含了响应式变量,那么它就是一个Hook
函数。
Hook实现原理
🐼看完上面的解释,我想你应该也能有所领悟,上面提到,所谓Hook
函数是指包含了响应式变量,能够让组件实现代码复用的函数。
🐼那在Vue3中,Hooks是基于Composition API实现的其实也不难理解,因为它需要基于响应式变量嘛!
🐼Hooks通过Vue3中setup函数来使用的,setup函数是Vue3组件中的一个新的生命周期函数,它在组件实例被创建之前调用,并且接收两个参数:props和context。在setup函数中,我们可以定义和返回组件中需要使用的响应式数据、方法、计算属性等,而这些都可以通过Hooks来实现。
Hook简单实现
知道了它是怎么个事?那我们怎么用呢!来和我一起探讨吧!
因为本篇文章更多的是想让大家明白hook函数,所以我们这里就举一个特别简单的例子!
业务需求:追踪鼠标位置
在一个夜黑风高的晚上,卷圣优哉游哉地喝着它的咖啡☕,此时它的后端小老弟给它发来信息,说,"大哥!不好了!这老板又改需求了!🤯说需要渲染出用户鼠标的实时位置,而且几乎每个页面都要!!你可能需要加一下班啊!"这时,可能普通程序员已经慌了,但作为一个资深大佬,我们已经很有经验了!
卷圣心想:我就简单地写个hook函数去追踪鼠标位置,然后再到不同视图组件里面去调用,再渲染一下不就成了......,卷圣回复说好的,明白了。
业务实现
没用hook前:
js
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>
这时,如果多个页面都同时需要的话,你复制这段代码跑来跑去,而且,你要知道的是,每个页面中的onMounted
跟onUnmounted
都不一定是空的,并且,变量的命名上,都有可能出现重复的情况发生。这在我们后期维护起来,是非常不方便的!那我们来看看帅气的hook方法吧!
用hook后:
主页面
js
<script setup>
import { useMouse } from './mouse.js'
const { x, y } = useMouse()
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>
在同一目录下新建mouse.js
文件,在文件内写入以下内容
js
// mouse.js
import { ref, onMounted, onUnmounted } from 'vue'
// 按照惯例,组合式函数名以"use"开头
export function useMouse() {
// 被组合式函数封装和管理的状态
const x = ref(0)
const y = ref(0)
// 组合式函数可以随时更改其状态。
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
// 一个组合式函数也可以挂靠在所属组件的生命周期上
// 来启动和卸载副作用
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
// 通过返回值暴露所管理的状态
return { x, y }
}
在这里,我们封装了一个hook库来实现鼠标追踪,若有其他组件需要使用,我们只需要将其引入,并使用变量即可,并不需要过多考虑变量重名,生命周期钩子代码过多问题!!当然,这里的逻辑比较清晰,当逻辑比较复杂的时候,你可能更能感受到它的强大!
这里介绍一个VueUse 库,它是Vue3生态中最受欢迎的第三方Hooks库之一,这里封装了很多hook函数,或许你能在其中找到或学习更为复杂的hook函数调用!VueUse中文文档 | VueUse中文文档 (vueusejs.com)
Hook的使用场景
-
逻辑复用:当多个组件需要共享相同的逻辑时,我们可以将这些逻辑封装成一个Hook,然后在需要的组件中导入并使用它。这样可以避免代码重复,提高代码的复用性。
-
逻辑拆分:对于复杂的组件,我们可以使用Hooks将组件的逻辑拆分成多个独立的函数,每个函数负责处理一部分逻辑。这样可以使组件的代码更加清晰、易于维护。
-
副作用管理:Hooks中的函数可以访问组件的响应式数据,并且可以在组件的生命周期中执行副作用操作(如定时器、事件监听等)。通过使用Hooks,我们可以更好地管理这些副作用操作,确保它们在组件卸载时得到正确的清理。
Vue3中的Hook与Vue2中的mixn
🐼可能你也感受到了,它有点像我们以前 Vue2 学习的mixn
!
🐼我们都知道 Vue3 引入 Composition API
的写法,当我们引入一个 hooks
函数的时候其实就像在 Vue2 中使用一个 mixin
一样,hooks
函数中的ref
,reactive
就相当于 mixin
中的data
,同时 hooks
还可以引入一些生命周期函数,watch
等在 mixin
中都有体现。下面简单展示一下 mixin
的写法,不过多讲解
定义
js
export const mixins = {
data() {
return {
msg: "",
};
},
computed: {},
created() {
console.log("我是mixin中的created生命周期函数");
},
mounted() {
console.log("我是mixin中的mounted生命周期函数");
},
methods: {
clickMe() {
console.log("我是mixin中的点击事件");
},
},
};
组件中使用
js
export default {
name: "App",
mixins: [mixins],
components: {},
created() {
console.log("组件调用minxi数据", this.msg);
},
mounted() {
console.log("我是组件的mounted生命周期函数");
},
};
用过 vue2 的 mixin
的都知道,它虽然可以封装一些逻辑,但是它同时也带来了一些问题。
比如你引入多个 mixin 它们的 data,methods 命名可能会冲突 ,当 mixin 多了可能会出现维护性问题,另外 mixin 不是一个函数,因此不能传递参数来改变它的逻辑,具有一定的局限性 等,但这些问题到了 vue3 的 hooks
中则迎刃而解
Hook优缺点
优点:
- 提高了代码的复用性和可维护性。
- 使组件的逻辑更加清晰、易于理解。
- 更好地管理组件的副作用操作。
缺点:
- 学习曲线较陡峭,需要熟悉新的编程模式和思维方式。
- 对于小型项目或简单组件,使用Hooks可能过于复杂。
- 在Vue生态中,第三方Hooks的质量和兼容性可能存在差异。
Hooks书写规范
- 命名规范 :自定义Hooks应该以"use"为前缀,以区分其他函数和变量。例如:
useUserInfo
、useMousePosition
等。同时,命名应清晰明了,准确描述Hooks的功能。 - 参数与返回值:自定义Hooks应该接收明确的参数,并返回需要在组件中使用的响应式数据、方法、计算属性等。返回的对象应该具有清晰的属性名和结构。
- 副作用管理 :如果自定义Hooks包含副作用操作(如定时器、事件监听等),应确保在组件卸载时正确清理这些副作用。可以使用
onMounted
、onUnmounted
等生命周期钩子来管理副作用的添加和移除。 - 文档注释:为自定义Hooks编写清晰的文档注释是非常重要的,说明其用途、参数、返回值和使用示例。这将有助于其他开发者理解和使用你的自定义Hooks。
- 类型定义(如果使用TypeScript):为自定义Hooks提供类型定义可以确保更好的类型安全性和编辑器支持。使用TypeScript的泛型功能可以增加Hooks的灵活性和可复用性。
- 测试:为自定义Hooks编写单元测试是确保其正确性和稳定性的重要手段。测试应该覆盖各种使用场景和边界情况。
总结
Vue3
中Hook
函数的写法还是比较吃香的,通过将响应式变量进行封装处理,以灵活的方式复用代码来实现不同组件的视图变化!通过本篇文章相信大家已经能对hooks
函数有一定的理解,目前很多开源项目都封装了大量的hooks
函数,学习它,让我们更优雅地进行开发吧!
笔者能力精力有限,有何错误,还望大家及时指出!