Vue 3 的自定义 Hooks(在 Vue 的官方术语中被称为组合式函数,Composables)是 Vue 3 Composition API 的核心实践之一。
简单来说,它就是一个封装了响应式逻辑的 JavaScript 函数。通过它,你可以将组件中的状态(逻辑)提取出来,实现跨组件的复用,让代码组织更清晰。
为了让你全面理解,我将从概念本质、实战案例、核心优势 以及最佳实践这几个维度为你详细拆解。
1. 什么是自定义 Hooks?
在 Vue 2 中,我们通常使用 mixin 来复用逻辑,但它存在命名冲突、来源不清晰等问题。Vue 3 的自定义 Hooks 本质上是一个函数,它利用 ref、reactive、watch 等 Composition API 封装逻辑,并返回响应式数据和方法。
- 命名规范 :约定俗成,函数名以
use开头,采用驼峰命名法(如useCounter、useMousePosition)。 - 存放位置 :通常在项目中创建
src/composables或src/hooks文件夹统一管理。
2. 核心实战案例
案例一:封装状态逻辑 (useCounter)
这是最基础的用法,将"计数器"相关的状态和方法抽离出来。
javascript
// composables/useCounter.js
import { ref, computed } from 'vue';
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
// 计算属性也可以封装
const doubleCount = computed(() => count.value * 2);
// 暴露出去供组件使用
return {
count,
doubleCount,
increment,
decrement
};
}
案例二:封装副作用与生命周期 (useMousePosition)
这是 Hooks 的精髓所在。它不仅封装数据,还封装了事件监听(副作用)以及组件卸载时的清理逻辑。
javascript
// composables/useMousePosition.js
import { ref, onMounted, onUnmounted } from 'vue';
export function useMousePosition() {
const x = ref(0);
const y = ref(0);
const update = (e) => {
x.value = e.clientX;
y.value = e.clientY;
};
onMounted(() => {
window.addEventListener('mousemove', update);
});
onUnmounted(() => {
window.removeEventListener('mousemove', update);
});
return { x, y };
}
在组件中使用
在 .vue 文件中,你可以像使用普通函数一样调用它,通过解构获取所需的状态和方法。
vue
<script setup>
import { useCounter } from './composables/useCounter';
import { useMousePosition } from './composables/useMousePosition';
// 直接调用,逻辑清晰
const { count, increment } = useCounter(10);
const { x, y } = useMousePosition();
</script>
<template>
<div>
<p>计数: {{ count }}</p>
<button @click="increment">加一</button>
<p>鼠标位置: {{ x }}, {{ y }}</p>
</div>
</template>
3. 为什么使用自定义 Hooks?(核心优势)
相比 Vue 2 的 Mixin,自定义 Hooks 具有压倒性的优势:
| 特性 | Vue 2 Mixin | Vue 3 自定义 Hooks |
|---|---|---|
| 命名冲突 | 容易发生(data、methods 合并) | 无冲突(通过解构赋值,可重命名) |
| 来源追踪 | 黑盒,不知道变量来自哪里 | 显式引入,一眼看清数据来源 |
| 逻辑组织 | 按选项组织(data/methods/separated) | 按功能组织,相关代码都在一起 |
| TypeScript | 类型推断困难 | 类型安全,支持完美的类型推导 |
4. 高级技巧与最佳实践
- 参数传递与复用 :Hooks 函数可以接收参数。例如封装一个通用的
useFetch,你可以传入不同的 URL,返回不同的数据,真正做到"通用"。 - 返回对象而非数组 :虽然 Vue 支持返回数组(类似 React),但官方推荐返回对象。因为对象解构支持重命名,避免了命名冲突,代码可读性更强。
- 及时清理副作用 :如果你在 Hook 中绑定了事件监听器、开启了定时器或 WebSocket 连接,务必 在
onUnmounted或onBeforeUnmount钩子中进行清理,防止内存泄漏。 - 结合 TypeScript:为你的 Hook 定义清晰的参数类型和返回值类型,能极大提升大型项目的开发体验和健壮性。
总结
Vue 3 的自定义 Hooks 不仅仅是一个语法特性,更是一种代码组织思想。它鼓励你将视图(UI)与逻辑(Logic)分离,将大而复杂的组件拆解为小而专注的函数。
当你发现有两处以上的代码在处理相同的响应式逻辑时,就是时候考虑封装一个 useXxx 了。