你是不是在学习 Vue 3 组合式 API(也叫 hooks)时,碰到过这个问题:每次调用自定义 hooks,都会新建一份数据吗?多个组件会不会互相影响?
今天这篇文章,带你彻底搞懂 Vue 3 hooks 的实例化机制!🌟
🧐 什么是 Vue 3 hooks?
在 Vue 3 里,hooks 通常指的是自定义的组合式函数(Composable),它们以 use
开头,可以封装逻辑,实现复用。比如最常见的 useMouse
、useFetch
、useCounter
等。
js
// useMouse.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
function update(e) {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
}
🤔 每次 useXXX 都是新建实例吗?
答案是:是的!每次调用自定义 hooks,都会新建一套"自己的"响应式数据和副作用。
🌱 以 useMouse
为例
js
const { x, y } = useMouse()
const { x: x2, y: y2 } = useMouse()
- 这两次调用,
x/y
和x2/y2
是完全独立的 响应式变量。 - 各自注册自己的事件监听(
mousemove
)。 - 互不影响,互不干扰。
🧩 为什么会这样?
因为每次调用 useMouse
,都会执行函数内部的代码,新建变量、注册副作用,这和普通函数没区别。每个组件、每次 setup
里调用的 hooks,都是独立的"副本"。
🧑💻 真实场景举例
1️⃣ 不同组件独立使用
js
// A.vue
const { x, y } = useMouse()
// B.vue
const { x, y } = useMouse()
- 组件 A 和 B 各自维护一份鼠标坐标,互不干扰。
2️⃣ 多次调用互不影响
js
// 在同一个组件 setup 里
const mouse1 = useMouse()
const mouse2 = useMouse()
mouse1
和mouse2
是完全独立的。
💡 如果想要全局共享怎么办?
有时候,我们希望多个组件(甚至全局)共享一份数据,比如只监听一次鼠标事件,所有组件都用同一份坐标。
这时候,可以把响应式数据和副作用提升到模块作用域。
🌍 全局单例写法
js
// useGlobalMouse.js
import { ref, onMounted, onUnmounted } from 'vue'
const x = ref(0)
const y = ref(0)
let isListening = false
function update(e) {
x.value = e.pageX
y.value = e.pageY
}
export function useGlobalMouse() {
if (!isListening) {
window.addEventListener('mousemove', update)
isListening = true
}
return { x, y }
}
- 不管你在哪个组件里调用
useGlobalMouse
,拿到的都是同一份响应式数据。 - 只会注册一次事件监听。
🎯 总结
- ✅ 每次调用自定义 hooks(如
useMouse
),都是新建一份响应式数据和副作用实例,互不影响。 - ✅ 如果想全局共享,可以把响应式数据和副作用写在模块作用域,实现单例模式。
- ✅ 理解这一点,有助于你更好地设计 hooks 逻辑,避免重复监听、数据错乱等问题!
📚 推荐阅读
希望本文能帮助你彻底理解 Vue 3 hooks 的实例化机制!如果觉得有收获,欢迎点赞、评论、关注我~
你的支持是我持续输出的动力!🔥🔥🔥
更多前端知识,持续更新中,敬请期待! 🚀🚀🚀