Vue3 把基于函数、可复用的逻辑片段统称为 组合式函数(Composables),日常大家口语都叫 hook,用法和 React Hook 思路类似,但 API、规则完全是 Vue 体系。
- Vue3 内置 Hook Vue 官方提供的原生 API:
ref/reactive/computed/watch/onMounted/useRoute等,是组合式 API 基础。 - 自定义 Hook(组合式函数) 把重复逻辑(窗口监听、请求、表单、权限、滚动条、本地存储等)抽成独立函数,多组件复用。
规范约定:Vue 自定义 Hook 函数名建议以
use开头(和 React 习惯一致,团队统一规范)。
Vue3 内置常用 Hook
1. 基础响应式
1.1 ref 基本类型响应(字符串 / 数字 / 布尔)
<template>
<div>{{ count }}</div>
<button @click="count++">+1</button>
</template>
<script setup>
// 导入内置 API
import { ref } from 'vue'
// 创建响应式变量
const count = ref(0)
// JS 中取值/赋值要加 .value
console.log(count.value)
</script>
1.2 reactive 对象 / 数组响应
import { reactive } from 'vue'
const user = reactive({
name: '张三',
age: 18
})
// 直接修改属性,不用 .value
user.name = '李四'
1.3 computed 计算属性(派生数据)
import { ref, computed } from 'vue'
const count = ref(0)
// 只读计算属性
const doubleCount = computed(() => count.value * 2)
2. 监听类 Hook
2.1 watch 监听数据变化
import { ref, watch } from 'vue'
const name = ref('')
// 监听 name
watch(name, (newVal, oldVal) => {
console.log('新值:', newVal)
}, { immediate: true }) // immediate 立即执行一次
2.2 watchEffect 自动收集依赖
不用指定监听谁,内部用到的响应式变了就执行:
watchEffect(() => {
console.log(name.value)
})
3. 生命周期 Hook(Vue3 组合式写法)
对应 Vue2 的生命周期,全部是函数形式:
import {
onMounted, // 挂载完成
onUpdated, // 更新完成
onUnmounted // 卸载销毁
} from 'vue'
// 组件挂载后执行(替代 mounted)
onMounted(() => {
console.log('组件已渲染到页面')
})
// 组件销毁前执行(清理定时器、监听、事件)
onUnmounted(() => {
console.log('组件销毁')
})
4. 路由 / 状态库常用(搭配生态)
Vue Router 4 Hook
import { useRoute, useRouter } from 'vue-router'
const route = useRoute() // 获取当前路由信息、参数
const router = useRouter() // 编程式跳转
console.log(route.path)
router.push('/login')
Pinia 状态库 Hook
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
console.log(userStore.token)
自定义 Hook(核心:逻辑复用)
规则
- 函数名 useXXX 开头;
- 内部可以使用所有 Vue 内置 API;
- 把需要复用的逻辑抽进去,返回变量 / 方法给组件使用;
- 一个 Hook 只做一件事(单一原则)。
1. 新建 Hook 文件 hooks/useWindowWidth.js
// 自定义 Hook:获取并监听浏览器窗口宽度
import { ref, onMounted, onUnmounted } from 'vue'
export function useWindowWidth() {
// 响应式变量保存窗口宽度
const windowWidth = ref(window.innerWidth)
// 更新宽度
const updateWidth = () => {
windowWidth.value = window.innerWidth
}
// 挂载时监听 resize
onMounted(() => {
window.addEventListener('resize', updateWidth)
})
// 销毁时移除监听(防止内存泄漏)
onUnmounted(() => {
window.removeEventListener('resize', updateWidth)
})
// 对外暴露变量
return { windowWidth }
}
封装「本地存储 localStorage」Hook
hooks/useLocalStorage.js
import { ref, watch } from 'vue'
export function useLocalStorage(key, defaultValue) {
// 读取本地值
const stored = localStorage.getItem(key)
const data = ref(stored ? JSON.parse(stored) : defaultValue)
// 变化自动同步到 localStorage
watch(
data,
(val) => {
localStorage.setItem(key, JSON.stringify(val))
},
{ deep: true }
)
return data
}
组件使用
<script setup>
import { useLocalStorage } from '@/hooks/useLocalStorage'
// 读写自动同步 localStorage
const token = useLocalStorage('token', '')
</script>
<template>
<div>Token:{{ token }}</div>
<button @click="token = '123456'">修改Token</button>
</template>
实战 3:封装「请求 Loading + 接口」Hook(业务最常用)
// hooks/useRequest.js
import { ref } from 'vue'
export function useRequest(apiFn) {
const loading = ref(false)
const data = ref(null)
const error = ref(null)
// 执行请求方法
const run = async (...args) => {
loading.value = true
error.value = null
try {
const res = await apiFn(...args)
data.value = res
} catch (err) {
error.value = err
} finally {
loading.value = false
}
}
return { loading, data, error, run }
}
使用
<script setup>
import { useRequest } from '@/hooks/useRequest'
import { getUserInfo } from '@/api/user'
const { loading, data, run } = useRequest(getUserInfo)
// 调用接口
run()
</script>
<template>
<div v-if="loading">加载中...</div>
<div v-else>{{ data?.name }}</div>
</template>
Vue Hook 和 React Hook 对比
- 调用时机
- Vue:可在
setup/ 自定义函数任意位置调用,不限制顺序 - React:必须在顶层,不能在条件、循环里调用,顺序不能变
- Vue:可在
- 响应式
- Vue:
ref/reactive原生响应,自动依赖收集 - React:靠
useState/useEffect手动监听
- Vue:
- 生命周期
- Vue:
onMounted等独立函数,可写多个 - React:统一在
useEffect模拟
- Vue:




