前言
在Vue3的开发世界中,Hooks是一项极具创新性和实用性的特性,它为开发者带来了全新的编程体验和诸多优势 , 越来越像 react 的风格。
什么是Vue3 Hooks
Vue3 Hooks本质上是基于Vue3的组合式API实现的一组可复用函数。
通过这些函数,开发者可以将组件中的逻辑代码进行抽离和封装,实现代码的复用和更好的组织架构。与Vue2中的混入(Mixin)类似,但Vue3 Hooks更清晰地展示了复用功能代码的来源,避免了Mixin可能出现的命名冲突、难以追踪来源等问题。
Vue3 Hooks的优势
提高代码复用性
将多个组件共享的逻辑封装成一个Hook,然后在需要的组件中导入并使用,避免了重复编写相同代码,提高了代码的复用率。例如,在多个组件中都需要实现获取用户信息的功能,就可以将这个逻辑封装成一个useUserInfo的Hook,在各个组件中直接调用。
增强逻辑清晰度
允许按照功能来组织代码,而不是像传统的Vue组件那样按照生命周期来组织。这样使得组件内部的逻辑更加清晰,易于理解和维护。比如,将与数据获取相关的逻辑放在一个Hook中,与表单验证相关的逻辑放在另一个Hook中,每个Hook都有明确的职责。
简化状态管理
使用reactive和ref等函数可以方便地创建响应式数据,提供了一种声明式的方式来处理数据变化,让状态管理变得更加直观。例如,通过ref创建一个响应式的计数器count,可以直接在模板中使用{{ count }}来显示计数器的值,并且当count的值发生变化时,模板会自动更新。
更好的副作用管理
可以使用onMounted、onUnmounted等生命周期钩子来管理副作用操作,如定时器、事件监听等。确保在组件卸载时正确清理这些副作用,避免内存泄漏等问题。比如,在onMounted钩子中添加一个事件监听,在onUnmounted钩子中移除该事件监听。
Vue3常用的Hooks函数
响应式数据相关
ref用于创建一个响应式的引用,常用于基本数据类型;reactive用于创建一个响应式的对象,常用于复杂数据类型;computed用于基于其他数据计算得出的数据属性,它具有缓存功能,只有在依赖的数据发生变化时才会重新计算。
生命周期相关
onMounted在组件挂载到DOM之后调用,常用于初始化数据、添加事件监听等操作;onBeforeUpdate在组件更新之前调用,可以在这个钩子中进行一些数据的预处理;onUnmounted在组件卸载之后调用,用于清理副作用,如清除定时器、移除事件监听等。
监听数据变化相关
watch和watchEffect用于监听数据变化并执行副作用。watch需要指定监听的数据源,而watchEffect会自动收集依赖的响应式数据,并在其变化时重新执行回调函数。
自定义Hooks
在Vue3中,开发者还可以自定义Hooks来满足特定的业务需求。自定义Hooks应该遵循一定的规范,以确保代码的可读性和可维护性。
命名规范:以“use”为前缀,例如useUserInfo、useMousePosition等。这样可以清晰地表明这是一个自定义的Hook函数。
参数与返回值:接收明确的参数,并返回需要在组件中使用的响应式数据、方法、计算属性等。返回的对象应该具有清晰的属性名和结构。
副作用管理:如果包含副作用操作,应确保在组件卸载时正确清理这些副作用。可以使用onMounted、onUnmounted等生命周期钩子来管理副作用的添加和移除。
我们举一个有副作用(内存泄漏)的代码 , 之后逐步改善为 hooks 风格
<template>
<div>
<p>Mouse X:{{ mousePos.x }}</p>
<p>Mouse Y:{{ mousePos.y }}</p>
</div>
</template>
<script setup>
import {reactive, onMounted , onUnmounted} from 'vue'
let mousePos = reactive({
x : 0,
y : 0
})
const mouseMoveHandler = (e)=>{
mousePos.x = e.clientX;
mousePos.y = e.clientY;
// 内存泄露
console.log("我还在~");
}
onMounted(()=>{
window.addEventListener('mousemove',)
})
</script>
<style scoped>
</style>
在卸载组件之后 , 控制台仍然显示“我还在~” , 监听事件没有卸载掉 ,造成内存泄露
于是我们利用 vue3 的生命周期 , 在组件卸载之后 ,清除事件监听
onUnmounted(()=>{
// 防止内存泄露
window.removeEventListener('mousemove',mouseMoveHandler)
console.log("我被移除了~");
})
效果如下 :
卸载组件之后 ,没有鼠标的事件监听就没了 ~
而使用 vue3 hooks 风格将会更加优雅 , 优雅永不过时 ~
我们将还有生命周期 和 响应式代码封装为 useMouse , 作为模块导出 , 从而实现 UI 与 State 分离 , 嚓 , 这是不是很 react , react 框架本身专注于视图 , 也是实现了业务与视图的分离 , 所以很适合大型项目
代码如下 :
<template>
<div>
<p>Mouse X:{{ x }}</p>
<p>Mouse Y:{{ y }}</p>
</div>
</template>
<script setup>
import { useMouse} from '../hooks/useMouse'
const { x, y } = useMouse()
// let mousePos = reactive({
// x: 0,
// y: 0
// })
// const mouseMoveHandler = (e) => {
// mousePos.x = e.clientX;
// mousePos.y = e.clientY;
// // 内存泄露
// console.log("我还在~");
// }
// onMounted(() => {
// window.addEventListener('mousemove',mouseMoveHandler)
// })
</script>
<style scoped></style>
import { ref, onMounted, onUnmounted } from 'vue';
// export 关键字就是模块化输出
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);
console.log('我还在~');
});
onUnmounted(() => {
window.removeEventListener('mousemove', update);
console.log('我被移除了~');
});
return { x, y };
}
场景
在实际项目中,Vue3 Hooks可以广泛应用于各种场景。
比如,在一个电商项目中,可以创建一个useCart的Hook来管理购物车的逻辑,包括添加商品、删除商品、计算总价等功能;
还可以创建一个useSearch的Hook来处理搜索功能,包括发送搜索请求、显示搜索结果等。通过使用自定义Hooks,将这些复杂的逻辑封装起来,使得组件的代码更加简洁和易于维护。
Vue3 Hooks是Vue3开发中的一项重要特性,提供了一种更加灵活、高效的方式来组织和复用代码。
通过合理地使用Vue3 Hooks,可以提高代码的质量和开发效率,让Vue3项目的开发更加轻松和愉快
作者:浪遏
链接:https://juejin.cn