在Vue 3中,Hooks主要基于Composition API实现,是一套用于组织和复用组件逻辑的函数。它们摆脱了Options API中"按选项分类"的限制,允许按"逻辑关注点"组织代码,大幅提升了代码的可复用性和可维护性。
一、基础Hooks(Composition API核心)
Vue 3内置了一系列基础Hooks,用于实现响应式、生命周期管理等核心功能。
1. 响应式相关Hooks
用于创建和管理响应式数据。
| Hook | 作用 | 示例 |
|---|---|---|
ref |
创建基本类型(或对象)的响应式数据(通过.value访问) |
javascript import { ref } from 'vue' const count = ref(0) // 读取:count.value // 修改:count.value++ |
reactive |
创建对象类型的响应式数据(直接访问属性) | javascript import { reactive } from 'vue' const user = reactive({ name: '张三', age: 20 }) // 读取:user.name // 修改:user.age = 21 |
computed |
创建计算属性(依赖响应式数据,自动缓存结果) | javascript import { ref, computed } from 'vue' const count = ref(1) const doubleCount = computed(() => count.value * 2) // 访问:doubleCount.value |
watch |
监听响应式数据变化(显式指定监听源) | javascript import { ref, watch } from 'vue' const count = ref(0) watch(count, (newVal, oldVal) => { console.log(`count从${oldVal}变成了${newVal}`) }) |
watchEffect |
自动追踪响应式依赖,依赖变化时执行(无需显式指定源) | javascript import { ref, watchEffect } from 'vue' const count = ref(0) watchEffect(() => { console.log(`count当前值:${count.value}`) // 自动追踪count }) |
2. 生命周期Hooks
对应Vue 2的生命周期函数,在Composition API中以函数形式存在,需在setup或<script setup>中使用。
| Hook | 对应Vue 2生命周期 | 作用 |
|---|---|---|
onMounted |
mounted |
组件挂载后执行 |
onUpdated |
updated |
组件更新后执行 |
onUnmounted |
unmounted |
组件卸载后执行 |
onBeforeMount |
beforeMount |
组件挂载前执行 |
onBeforeUpdate |
beforeUpdate |
组件更新前执行 |
onBeforeUnmount |
beforeDestroy |
组件卸载前执行 |
onErrorCaptured |
- | 捕获子组件错误时执行 |
onActivated |
- | 缓存组件(<KeepAlive>)激活时执行 |
onDeactivated |
- | 缓存组件失活时执行 |
示例:
代码语言:javascript
AI代码解释
javascript
import { onMounted, onUnmounted } from 'vue'
onMounted(() => {
console.log('组件挂载完成')
// 例如:初始化定时器、事件监听
})
onUnmounted(() => {
console.log('组件卸载完成')
// 例如:清除定时器、事件监听
})
3. 其他基础Hooks
| Hook | 作用 | 示例 |
|---|---|---|
toRef |
将响应式对象的属性转为ref(保持响应式关联) |
javascript import { reactive, toRef } from 'vue' const user = reactive({ name: '张三' }) const nameRef = toRef(user, 'name') // 修改nameRef会同步到user.name |
toRefs |
将响应式对象的所有属性转为ref对象(用于解构) |
javascript import { reactive, toRefs } from 'vue' const user = reactive({ name: '张三', age: 20 }) const { name, age } = toRefs(user) // 解构后仍保持响应式 |
shallowRef |
创建"浅响应式"数据(仅顶层响应式) | javascript import { shallowRef } from 'vue' const obj = shallowRef({ a: 1 }) // 修改obj.value.a不会触发更新,需重新赋值obj.value才会更新 |
shallowReactive |
创建"浅响应式"对象(仅顶层属性响应式) | javascript import { shallowReactive } from 'vue' const obj = shallowReactive({ a: 1, b: { c: 2 } }) // 修改obj.a会触发更新,修改obj.b.c不会 |
readonly |
创建只读响应式数据(禁止修改) | javascript import { reactive, readonly } from 'vue' const user = reactive({ name: '张三' }) const readOnlyUser = readonly(user) // 修改readOnlyUser.name会报错 |
二、自定义Hooks
自定义Hooks是Vue Hooks的核心价值所在,用于封装可复用的逻辑(如数据请求、本地存储、事件监听等),命名通常以use开头(如useFetch、useLocalStorage)。
1. 自定义Hooks的特点
- 必须是函数,且命名以
use开头(约定); - 内部可调用Vue内置Hooks(如
ref、onMounted); - 可返回响应式数据、方法等,供组件使用。
2. 常用自定义Hooks示例
示例1:useFetch(封装API请求逻辑)
代码语言:javascript
AI代码解释
csharp
// hooks/useFetch.js
import { ref, onMounted, watch } from 'vue'
export function useFetch(url) {
const data = ref(null)
const loading = ref(false)
const error = ref(null)
// 定义请求方法
const fetchData = async () => {
loading.value = true
error.value = null
try {
const res = await fetch(url)
data.value = await res.json()
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
}
// 组件挂载时请求
onMounted(fetchData)
// 监听url变化,自动重新请求
watch(url, fetchData)
// 返回响应式数据和方法
return { data, loading, error, refetch: fetchData }
}
组件中使用:
代码语言:vue
AI代码解释
xml
<template>
<div>
<div v-if="loading">加载中...</div>
<div v-if="error">错误:{{ error }}</div>
<ul v-if="data">
<li v-for="item in data" :key="item.id">{{ item.name }}</li>
</ul>
<button @click="refetch">重新加载</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useFetch } from './hooks/useFetch'
const url = ref('https://api.example.com/data')
const { data, loading, error, refetch } = useFetch(url)
</script>
示例2:useLocalStorage(封装本地存储逻辑)
代码语言:javascript
AI代码解释
javascript
// hooks/useLocalStorage.js
import { ref, watch } from 'vue'
export function useLocalStorage(key, defaultValue) {
// 从localStorage读取初始值
const value = ref(
JSON.parse(localStorage.getItem(key)) || defaultValue
)
// 监听值变化,同步到localStorage
watch(value, (newVal) => {
localStorage.setItem(key, JSON.stringify(newVal))
}, { deep: true }) // deep: true 确保对象修改也能被监听
// 返回响应式数据和清除方法
return {
value,
clear: () => {
value.value = defaultValue
localStorage.removeItem(key)
}
}
}
组件中使用:
代码语言:vue
AI代码解释
xml
<script setup>
import { useLocalStorage } from './hooks/useLocalStorage'
// 存储用户偏好设置
const { value: userSettings, clear } = useLocalStorage(
'user-settings',
{ theme: 'light', notifications: true }
)
// 修改值会自动同步到localStorage
userSettings.value.theme = 'dark'
// 清除存储
// clear()
</script>
示例3:useWindowSize(监听窗口大小变化)
代码语言:javascript
AI代码解释
javascript
// hooks/useWindowSize.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useWindowSize() {
const width = ref(window.innerWidth)
const height = ref(window.innerHeight)
const updateSize = () => {
width.value = window.innerWidth
height.value = window.innerHeight
}
// 挂载时监听窗口 resize 事件
onMounted(() => {
window.addEventListener('resize', updateSize)
})
// 卸载时移除监听(避免内存泄漏)
onUnmounted(() => {
window.removeEventListener('resize', updateSize)
})
return { width, height }
}
组件中使用:
代码语言:vue
AI代码解释
xml
<template>
<div>窗口大小:{{ width }} × {{ height }}</div>
</template>
<script setup>
import { useWindowSize } from './hooks/useWindowSize'
const { width, height } = useWindowSize()
</script>
三、Hooks使用最佳实践
- 单一职责 :一个自定义Hooks只封装一个逻辑关注点(如
useFetch只处理请求,useLocalStorage只处理本地存储)。 - 避免过度封装:简单逻辑无需抽为Hooks,避免增加复杂度。
- 清理副作用 :在
onUnmounted中清除定时器、事件监听等,避免内存泄漏。 - 命名规范 :自定义Hooks以
use开头(如useForm、useAuth),便于识别。 - 组合复用 :多个Hooks可相互组合使用(如
useFetch中可调用useLocalStorage缓存数据)。
总结
Vue Hooks(基于Composition API)通过函数式编程的方式,解决了Options API中逻辑复用难、代码分散的问题。内置Hooks提供了响应式、生命周期等基础能力,而自定义Hooks则是实现逻辑复用的核心,让组件代码更简洁、可维护性更高。
实际开发中,可根据业务场景封装更多自定义Hooks(如表单处理useForm、权限控制usePermission等),大幅提升开发效率。