Vue3核心语法进阶(Hook)
Vue3 自定义 Hook:让你的代码像乐高一样“可复用”!
大家好,我是你们的前端小伙伴!上一篇我们聊了 Vue3 的生命周期,今天咱们继续深入 Vue3 的核心利器——自定义 Hook(Custom Hook)。
如果你已经用过 ref
、reactive
、watch
、onMounted
这些 Composition API,那你已经“会用工具了”。而今天我们要学的,是如何把一堆工具打包成一个“超级工具包”,哪里需要就往哪里一放,功能立马就有了!
这个“超级工具包”,就是 自定义 Hook。
什么是自定义 Hook?
想象一下,你在写一个电商网站,有 5 个页面都需要“获取用户信息 + 检查登录状态 + 显示用户头像”。
如果你在每个页面都重复写一遍:
const userInfo = ref(null)const isLoggedIn = ref(false)onMounted(async () => { const data = await fetch(\'/api/user\') userInfo.value = data isLoggedIn.value = data ? true : false})watch(userInfo, (newVal) => { if (newVal) console.log(\'用户已登录\')})
那……恭喜你,代码已经“复制粘贴”了 5 遍!如果哪天接口变了,你得改 5 个地方,想想都头大。
自定义 Hook 就是:把这段“通用逻辑”抽出来,变成一个函数,谁需要谁调用!
自定义 Hook 的本质
它就是一个以 use
开头的普通函数,比如 useUser
、useCart
、useLocalStorage
。
它内部可以使用任何 Composition API(ref
、watch
、onMounted
等),然后把需要暴露的数据和方法 return 出去。
动手写一个:useUser()
用户信息 Hook
我们来写一个真正可用的自定义 Hook!
// composables/useUser.jsimport { ref, onMounted, watch } from \'vue\'export function useUser() { const userInfo = ref(null) const isLoggedIn = ref(false) const loading = ref(true) // 模拟请求用户数据 const fetchUser = async () => { loading.value = true try { const res = await fetch(\'/api/user\') const data = await res.json() userInfo.value = data isLoggedIn.value = !!data } catch (err) { console.error(\'获取用户失败\', err) } finally { loading.value = false } } // 组件挂载时自动获取用户 onMounted(() => { fetchUser() }) // 监听用户信息变化 watch(userInfo, (newVal) => { if (newVal) { console.log(`欢迎回来,${newVal.name}!`) } }) // 把你需要的东西 return 出去 return { userInfo, isLoggedIn, loading, fetchUser // 也可以手动刷新 }}
文件名建议:
composables/useXxx.js
,这是 Vue 社区的约定。
在组件中使用它
现在,任何组件只要想用“用户逻辑”,一句话搞定:
import { useUser } from \'@/composables/useUser\'// 一行代码,搞定用户逻辑!const { userInfo, isLoggedIn, loading, fetchUser } = useUser() 加载中... 欢迎,{{ userInfo.name }}!
请先登录
看到了吗?组件代码变得极其干净,逻辑都被“封装”到
useUser
里了。
自定义 Hook 的核心优势
useUser
函数,不用渲染组件高级用法:支持参数和返回函数
自定义 Hook 不只是“固定逻辑”,它也可以很灵活!
示例:useLocalStorage
—— 让数据自动存到本地
// composables/useLocalStorage.jsimport { ref, watch } from \'vue\'export function useLocalStorage(key, initialValue) { // 从 localStorage 读取,或用默认值 const data = ref( JSON.parse(localStorage.getItem(key)) || initialValue ) // 数据变化时,自动存到 localStorage watch(data, (newVal) => { localStorage.setItem(key, JSON.stringify(newVal)) }, { deep: true }) // deep: true 支持对象/数组 return data}
使用它:
// 计数器,刷新页面也不会丢!const count = useLocalStorage(\'count\', 0)// 用户设置const settings = useLocalStorage(\'userSettings\', { theme: \'dark\' })
看,一个 Hook,支持任意 key 和默认值,真正做到了“通用”!
常见误区 & 注意事项
误区 1:在普通函数里用 ref
就是 Hook?
No!只有在 setup
或 中调用的函数,才能使用 Composition API。你的
useXxx
函数必须在组件上下文中调用。
误区 2:Hook 可以 return 模板?
不能!Hook 只负责逻辑和数据,模板还是得在组件里写。
最佳实践:命名规范
- 一定要以
use
开头,比如useMouse
、useScroll
、useFetch
- 返回值尽量结构清晰,方便解构使用
- 复杂逻辑可以拆分成多个小 Hook
实战案例:useMouse
—— 跟踪鼠标位置
// composables/useMouse.jsimport { ref, onMounted, onUnmounted } from \'vue\'export function useMouse() { 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 }}
使用:
import { useMouse } from \'@/composables/useMouse\'const { x, y } = useMouse() 鼠标位置:{{ x }}, {{ y }}
瞬间,你的组件就有了“追踪鼠标”的超能力!
为什么叫“Hook”?
“Hook” 的意思是“钩子”,它就像是把一段逻辑“钩”进组件的生命周期中。
比如 onMounted
就是一个“钩子”,告诉 Vue:“等组件挂载后,执行我这个函数”。
而自定义 Hook,就是把多个钩子和逻辑打包,变成一个可复用的“增强包”。
总结:自定义 Hook 的灵魂
useXxx()
函数,返回响应式数据和方法最后一句话
组件负责“长什么样”,Hook 负责“怎么动”。
把通用逻辑封装成 Hook,你的代码就会像乐高积木一样,拼装自由,复用无忧!