Vue3中hooks详解
- 一、 核心概念
- 1. 什么是 Composable?
- 2. 为什么需要它?
- 二、 基本结构与规范
- 三、 常见应用场景与示例
- 1. 鼠标位置追踪 (`useMouse`)
- 2. 网络请求封装 (`useFetch`)
- 3. 本地存储同步 (`useLocalStorage`)
- 四、 最佳实践与注意事项
- 五、 总结
在 Vue 3 中,Hooks(钩子函数) 通常指的是组合式函数(Composables)。这是一种基于组合式 API(Composition API)的代码复用和组织逻辑的模式。它允许你将组件中的状态和逻辑提取到独立的函数中,从而实现逻辑的复用、解耦和更好的可测试性。
一、 核心概念
1. 什么是 Composable?
* 它是一个函数,利用 Vue 的组合式 API(如 `ref`, `reactive`, `computed`, `watch`, `onMounted`等)来封装和复用有状态逻辑。 * 约定俗成地,Composable 函数名以 `use` 开头(例如 `useMouse`, `useFetch`),以便识别。2. 为什么需要它?
* 逻辑复用:解决 Vue 2 中 Mixins 存在的命名冲突、来源不清晰等问题。 * 代码组织将相关逻辑(状态 + 方法 + 副作用)聚合在一起,而不是分散在 `data`, `methods`, `mounted` 等选项中。 * 灵活性:可以嵌套使用,一个 Composable 可以调用另一个 Composable。二、 基本结构与规范
一个标准的 Composable 函数通常包含以下部分:
// useCounter.jsimport{ref,computed}from'vue'exportfunctionuseCounter(initialValue=0){// 1. 定义响应式状态constcount=ref(initialValue)// 2. 定义计算属性或方法constdouble=computed(()=>count.value*2)functionincrement(){count.value++}functiondecrement(){count.value--}// 3. 返回需要暴露给组件使用的状态和方法return{count,double,increment,decrement}}在组件中使用:
<script setup>import{useCounter}from'./useCounter'// 调用 hook,获取状态和方法const{count,double,increment,decrement}=useCounter(10)</script><template><div><p>Count:{{count}}</p><p>Double:{{double}}</p><button @click="increment">+</button><button @click="decrement">-</button></div></template>三、 常见应用场景与示例
1. 鼠标位置追踪 (useMouse)
监听鼠标移动事件,返回当前坐标。
// useMouse.jsimport{ref,onMounted,onUnmounted}from'vue'exportfunctionuseMouse(){constx=ref(0)consty=ref(0)constupdate=(event)=>{x.value=event.pageX y.value=event.pageY}onMounted(()=>window.addEventListener('mousemove',update))onUnmounted(()=>window.removeEventListener('mousemove',update))return{x,y}}2. 网络请求封装 (useFetch)
封装通用的异步数据获取逻辑,处理加载状态、错误和数据。
// useFetch.jsimport{ref,watchEffect}from'vue'exportfunctionuseFetch(url){constdata=ref(null)consterror=ref(null)constloading=ref(true)constfetchData=async()=>{loading.value=truetry{constres=awaitfetch(url)if(!res.ok)thrownewError('Network response was not ok')data.value=awaitres.json()}catch(err){error.value=err.message}finally{loading.value=false}}// 当 url 变化时重新获取数据watchEffect(()=>{fetchData()})return{data,error,loading}}3. 本地存储同步 (useLocalStorage)
将响应式数据同步到浏览器的 `localStorage。
// useLocalStorage.jsimport{ref,watchEffect}from'vue'exportfunctionuseLocalStorage(key,defaultValue){conststoredValue=localStorage.getItem(key)conststate=ref(storedValue?JSON.parse(storedValue):defaultValue)watchEffect(()=>{localStorage.setItem(key,JSON.stringify(state.value))})returnstate}四、 最佳实践与注意事项
命名规范:始终以
use开头,后跟描述性功能名称(驼峰命名法)。返回值:始终返回一个对象,包含组件需要访问的状态和方法。即使只返回一个值也建议包裹在对象中,保持接口一致性和未来扩展性。
避免副作用泄露:确保在
onUnmounted中清理事件监听器、定时器等,防止内存泄漏。参数化:通过函数参数接收配置项或初始值,提高 Hook 的通用性。
不要直接修改传入的 Ref:如果 Hook 接收
ref作为参数,应避免直接替换该ref对象,而是修改其.value。如果需要替换,应返回新的ref。类型支持(TypeScript):为 Composable 函数添加明确的类型定义,提升开发体验和代码健壮性。
// useCounter.tsimport{ref,Ref}from'vue'exportfunctionuseCounter(initialValue:number=0){constcount:Ref<number>=ref(initialValue)// ...return{count,/* ... */}}与 Pinia/Vuex 的区别:
- Composables:侧重于逻辑复用,状态通常局限于使用该 Hook 的组件实例(除非特意共享)。每个组件调用
useXxx()通常会获得独立的状态副本。 - Pinia/Vuex:侧重于全局状态管理,状态是单例的,所有组件共享同一份状态。
- Composables:侧重于逻辑复用,状态通常局限于使用该 Hook 的组件实例(除非特意共享)。每个组件调用
五、 总结
Vue 3 的 Hooks/Composables 是构建大型、可维护应用的关键工具。它们通过函数式的组合方式,实现了比 Mixins 更清晰、更灵活、更类型安全的逻辑复用。掌握 Composables 的编写和使用,是深入理解 Vue 3 组合式 API 的核心。