
前言
在 Vue.js 应用开发中,随着业务逻辑的复杂化,组件常常需要处理重复的逻辑(如数据获取、表单验证、事件监听、全局状态管理)。传统的做法是将这些逻辑直接写在组件内部,导致代码冗余、难以维护,且违反"关注点分离"原则。Vue 3 引入的组合式 API(Composition API)为逻辑复用提供了更优雅的解决方案:Vue Hook,能够将状态、方法和生命周期钩子等逻辑独立出来,从而让组件代码更加清晰、易于维护。
一、核心概念与作用
1.1 什么是 Vue Hooks
Hooks 并不是 Vue 特有的概念,它最初来源于 React 16 之后的一种新的函数式编程思维。在 React 中,Hooks 提供了一系列以 use 开头的函数,允许开发者在函数式组件中完成生命周期、状态管理、逻辑复用等几乎全部组件开发工作。

在Vue 3中,Hooks 结合了 Vue 的响应式系统,成为了一种强大的状态逻辑封装与复用机制。允许开发者将Vue组件的逻辑拆分成多个独立的、可复用的函数,这些函数就被称为 Hooks。每个 Hooks 都封装了一段具有状态逻辑的代码,可以在多个组件中共享和复用。
1.2 核心价值
- 逻辑复用:将通用逻辑(如数据请求、表单验证、鼠标追踪)封装成独立函数,避免代码重复。相比 Vue 2 的 Mixins,Hooks 避免了命名冲突和来源不明的问题。
- 代码组织更清晰:按"逻辑关注点"而非"选项类型"组织代码。例如,将一个功能相关的状态、方法、生命周期钩子放在一起,而不是分散在 data、methods、mounted 中。
- 更好的 TypeScript 支持:基于函数的组合天然适合类型推导,无需额外配置即可获得精准的类型提示。
- 简化复杂组件:大型组件可拆分为多个小的 Hook,每个 Hook 负责单一职责,提升可维护性。
二、基础 Hooks 分类
Vue 3 内置了一系列基础 Hooks,用于实现响应式、生命周期管理等核心功能。
2.1 响应式状态
用于创建和管理响应式数据,如下表所示。
| Hook | 作用 |
|---|---|
| ref | 创建基本类型(或对象)的响应式数据(通过.value访问) |
| reactive | 创建对象类型的响应式数据(直接访问属性) |
| toRef | 将响应式对象的属性转为ref(保持响应式关联) |
| toRefs | 将响应式对象的所有属性转为ref对象(用于解构) |
| watch | 监听响应式数据变化(显式指定监听源) |
| watchEffect | 自动追踪响应式依赖,依赖变化时执行(无需显式指定源) |
html
<script setup lang="ts">
import { ref, reactive, toRef, toRefs } from 'vue'
const count = ref(0)
const user = reactive({ name: '张三', age: 20 })
const nameRef = toRef(user, 'name')
const { name, age } = toRefs(user) // 解构后仍保持响应式
</script>
2.2 计算与监听
| Hook | 作用 |
|---|---|
| computed | 创建计算属性(依赖响应式数据,自动缓存结果) |
| watch | 监听响应式数据变化(显式指定监听源) |
| watchEffect | 自动追踪响应式依赖,依赖变化时执行(无需显式指定源) |
html
<script setup lang="ts">
import { ref, computed, watchEffect } from 'vue'
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
watchEffect(() => {
console.log(`count当前值:${count.value}`)
})
</script>
2.3 生命周期Hooks
在 Composition API 中以函数形式存在,需在 setup 或 <script setup> 中使用。
| Hook | 对应Vue 2生命周期 | 作用 |
|---|---|---|
| onMounted | mounted | 组件挂载后执行 |
| onUpdated | updated | 组件更新后执行 |
| onUnmounted | unmounted | 组件卸载后执行 |
| onBeforeMount | beforeMount | 组件挂载前执行 |
| onBeforeUpdate | beforeUpdate | 组件更新前执行 |
| onBeforeUnmount | beforeDestroy | 组件卸载前执行 |
| onErrorCaptured | 捕获子组件错误时执行 | |
| onActivated | 缓存组件(KeepAlive)激活时执行 | |
| onDeactivated | 缓存组件失活时执行 |
html
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue'
onMounted(() => {
console.log('组件挂载完成')
// 例如:初始化定时器、事件监听
})
onUnmounted(() => {
console.log('组件卸载完成')
// 例如:清除定时器、事件监听
})
</script>
2.4 其他基础Hooks
| Hook | 作用 |
|---|---|
| shallowRef | 创建"浅响应式"数据(仅顶层响应式) |
| shallowReactive | 创建"浅响应式"对象(仅顶层属性响应式) |
| readonly | 创建只读响应式数据(禁止修改) |
html
<script setup lang="ts">
import { reactive, toRef, toRefs, shallowRef, readonly } from 'vue'
const user = reactive({ name: '张三', age: 20 })
const nameRef = toRef(user, 'name')
const { name, age } = toRefs(user) // 解构后仍保持响应式
const obj = shallowRef({ a: 1 }) // 修改obj.value.a不会触发更新,需重新赋值obj.value才会更新
const readOnlyUser = readonly(user) // 修改readOnlyUser.name会报错
</script>
三、Hooks 的基本使用
在 Vue3 中,自定义 Hooks 函数是提升代码复用性和组织性的重要手段,可以将状态管理、业务逻辑等封装在自定义 Hook 中。这些函数是使用 Composition API 创建的,可以包含任意的组合逻辑,并且可以在多个组件之间共享。通过封装可复用的逻辑代码,开发者可以更加高效地构建和维护大型应用。
3.1 创建 Hooks 函数
一般我们会在 src 文件夹下新建一个 hooks 文件夹,用于统一存放程序中用到的 hooks 代码。下面结合实例来写一个简单的 hooks,如下图所示。

自定义 Hook 是一个普通的 JavaScript 函数,通常以 use 开头命名,它可以使用 Composition API 提供的函数来管理状态和副作用。我们在 src 文件夹下新建 hooks 文件夹后,在里面新建一个 useCounter.js 文件,代码如下:
javascript
import { ref } from 'vue'
// 定义一个名为useCounter的Hook
export function useCounter(initVal = 0) {
// 定义一个响应式状态
const count = ref(initVal);
// 定义一个增加状态的方法
const increment = () => {
count.value++;
};
// 定义一个减少状态的方法
const decrement = () => {
count.value--;
};
// 定义一个重置状态的方法
const reset = () => {
count.value = initVal;
};
// 返回状态和方法供外部调用
return { count, increment, decrement, reset };
}
3.2 使用自定义 Hook
在上面的示例中,我们定义了一个名为 useCounter 的 Hook,它封装了一个响应式状态和三个操作状态的方法。使用自定义 Hooks 非常简单,只需在组件的 <script setup> 中引入并调用,解构出所需的属性和方法即可直接在模板中使用:
html
<script setup>
import { useCounter } from '@/hooks/useCounter'
// 直接解构即用,无需重复定义变量
const { count, increment, reset } = useCounter(10)
</script>
<template>
<div>当前计数: {{ count }}</div>
<button @click="increment">+</button>
<button @click="reset">重置</button>
</template>
在上面的示例中,在组件的 setup 函数中,调用useCounter Hook 获取状态和方法,并将其暴露给模板使用。这样,我们就成功地实现了状态的封装和复用。
四、Hooks 的最佳实践
4.1 设计原则
自定义 Hooks 是为了处理组件逻辑的一种模式,它可以让我们在不使用组件之间复制粘贴代码的情况下重用状态逻辑。自定义 hooks 是简单的 JavaScript 函数,但是在使用时,需要遵循以下:
- 命名规范:使用 use 前缀来命名 Hooks 函数,以区别于普通的 JavaScript 函数,例如 useCounter、useFetch 等。
- 单一职责原则:每个 Hooks 函数应该只负责一项功能,例如 useLocalStorage 负责本地存储操作,这有助于保持代码的可读性和可维护性,避免将多个不相关逻辑混入同一 Hooks。
- 避免副作用:尽量将副作用(如 DOM 操作、网络请求等)放在生命周期钩子中处理,而不是直接在 Hooks 函数内部进行。
- 参数化:为了使 Hooks 函数更加通用,可以通过参数来传递不同的配置或初始值。
- 组合与嵌套:Hooks 函数之间可以相互调用和组合,从而构建出更复杂的功能,但需要注意避免循环依赖和无限递归。
- 文档与注释:为 Hooks 函数添加适当的文档和注释,说明其用途、参数和返回值,这将有助于其他开发者理解和使用 Hooks 函数。
五、总结
Hooks 作为 Vue 3 中引入的一种新的状态逻辑封装与复用机制,为我们提供了一种更加灵活和高效的方式来组织和复用代码。通过学习和掌握 Hooks 的使用,我们可以更好地应对复杂的 Vue 项目开发需求,提高代码的可维护性和可读性。同时,Hooks 也为我们提供了一种全新的函数式编程思维方式,有助于我们更好地理解和掌握 Vue 的开发精髓。
