引言
在Vue3中,hooks
并不是官方定义的术语,而是开发者对 Composition API 的编程风格的俗称,在React的hooks
为函数组件引入了状态和其他React特性,而Vue3就是借鉴了这种思想从而推出的 Composition API。
何为 Hooks
hooks
直译为 钩子 ,理所当然Hook function
也被称为 钩子函数。可以将hooks
当作鱼钩,将鱼钩抛入水中,在鱼上钩时会返还一个信号给我们,让我们知道鱼上钩了,而hooks
在Vue中的作用也差不多,它在代码中会在特定的时机"钩住"一些东西--例如组件的生命周期、状态变化等,并且返还一个信号给我们,这样就可以对这些情况做出反应。
例如:
- 生命周期钩子:当组件挂载(
onMounted
)或卸载(onUnmounted
)时,"钩子"就会触发,这时我们就可以执行相应的逻辑。 - 状态变化钩子:通过
watch
或watchEffect
,我们可以"钩住"某个响应式数据的变化,并在数据更新时执行副作用操作。
何为副作用?
"副作用"指与组件渲染无关的操作,比如:
- 定时器
- 事件监听
- 直接操作 DOM 元素
这些操作会影响组件之外的状态或行为,所以需要管理它们的生命周期,以防内存泄露 或意外行为
当然其特性不止于此:
- 拆分逻辑:将组件中复杂的业务逻辑抽离成多个独立的函数,每个函数负责处理一部分逻辑。
- 复用逻辑:多个组件可以共享拆分出的函数,当然前提是它们的需要这个业务逻辑。
普通封装函数 vs Hook函数
普通封装的工具函数通常不依赖任何的特定状态或上下文环境,并且不会直接与视图层发生交互(不会自动触发视图更新),例如普通的计算函数:
js
function add(a, b){
return a + b;
}
而Hook函数通常包含响应式变量(如ref
、reactive
创建的变量),并且能够监听这些变量的变化来触发视图更新。
js
import { ref } from 'vue';
// Hook函数
function useCounter(initialValue = 0) {
const count = ref(initialValue); // 响应式变量
const increment = () => ++count.value;
const decrement = () => --count.value;
return { count, increment, decrement };
}
所以,如何判断一个函数为Hook函数,那么就看其内部是否包含响应式数据。
Hooks 的基本使用
1.命名规范
自定义的 hook
函数有一个默认的规矩,那就是命名通常用use
开头,例如:useMouse
等。(帮助区分普通函数和hook函数)
2.避免直接操作 DOM
直接操作 DOM(如使用 document.getElementById
)会破坏 hook函数 声明式的设计,可能导致与 Vue 的响应式系统冲突,如果需要访问请通过ref
和onMounted
。
3.确保清理副作用
如果 hook函数 中涉及副作用,必须在组件卸载时清理这些副作用,否则可能引发内存泄漏或逻辑错误。
4.避免过度抽象
虽然 hooks 提供了很好的复用性,但不要为了复用而过度抽象。将 hook函数 的职责单一化,专注于解决一个具体的问题。
创建自定义的 Hook
这里我用一个简单的追踪鼠标位置,并且包含开关显示位置的按钮的样例来做演示
js
// useMouse.js(建议用单独用一个hooks文件夹存放 hook函数)
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
let x = ref(0),
y = ref(0);
const mousePosHandler = (e) => {
x.value = e.pageX
y.value = e.pageY
console.log('我还在移动')
}
// -----------------管理副作用----------------------------------
// 注册事件监听器
onMounted(() => {
window.addEventListener('mousemove', mousePosHandler)
})
// 移除事件监听器
onUnmounted(() => {
window.removeEventListener('mousemove', mousePosHandler)
})
return { x, y }
}
export function useMemo() {
console.log('userMemo')
}
使用样例
调用 hook
函数并解构返回即可
html
<!-- MousePos.vue -->
<template>
<div>
<p>Mouse X: {{ x }}</p>
<p>Mouse Y: {{ y }}</p>
</div>
</template>
<script setup>
import { useMouse, useMemo } from '../hooks/useMouse'
const { x , y } = useMouse()
useMemo()
</script>
<style scoped>
</style>
html
<!-- App.vue -->
<script setup>
import {
ref
} from 'vue'
import MousePos from './components/MousePos.vue'
const showMouse = ref(true);
const toggleMouse = () => {
showMouse.value = !showMouse.value;
}
</script>
<template>
<div>
<MousePos v-if="showMouse"/>
<button @click="toggleMouse">切换显示</button>
</div>
</template>
<style scoped>
</style>
最终效果
官方文档:VueHook Plus