在 Vue 3 中,Composition API 的引入带来了全新的组件开发模式。Hooks(通常以 use 开头的函数)作为 Composition API 的核心特性,允许开发者以函数形式组织和复用组件逻辑,彻底改变了传统 Options API 中基于配置对象的开发方式。相比之下,Hooks 具有以下显著优势:
本文将通过具体案例,从基础用法到复杂异步场景,全面解析 Vue3 Hooks 的核心玩法。
Hooks 是一个返回对象(包含响应式数据、方法、生命周期钩子)的函数,本质是对 Vue 响应式系统和生命周期的封装。典型结构如下:
import { ref, onMounted } from 'vue';
export function useCounter(initialValue = 0) {
// 响应式状态
const count = ref(initialValue);
// 生命周期钩子
onMounted(() => {
console.log('Counter mounted');
});
// 业务逻辑
const increment = () => count.value++;
const decrement = () => count.value--;
// 暴露接口
return { count, increment, decrement };
}
在
import { ref, onMounted, onUnmounted } from 'vue';
export function useFetch(url) {
const data = ref(null);
const error = ref(null);
const loading = ref(true);
let abortController;
const fetchData = async () => {
try {
abortController = new AbortController();
const response = await fetch(url, { signal: abortController.signal });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
data.value = await response.json();
} catch (err) {
if (err.name !== 'AbortError') {
error.value = err;
}
} finally {
loading.value = false;
}
};
onMounted(fetchData);
onUnmounted(() => abortController?.abort());
return { data, error, loading, refetch: fetchData };
}
关键特性解析:
import { ref, watch } from 'vue';
export function useSearch() {
const query = ref('');
const results = ref([]);
const loading = ref(false);
const error = ref(null);
let timeoutId;
const search = async (newQuery) => {
if (!newQuery.trim()) {
results.value = [];
return;
}
clearTimeout(timeoutId);
loading.value = true;
error.value = null;
timeoutId = setTimeout(async () => {
try {
const response = await fetch(
`https://api.example.com/search?q=${encodeURIComponent(newQuery)}`
);
results.value = await response.json();
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
}, 300); // 300ms 防抖延迟
};
watch(query, (newVal) => search(newVal));
return { query, results, loading, error };
}
优化点:
当需要同时获取多个关联数据时,可以在 Hook 中组合使用其他 Hook:
import { ref, onMounted } from 'vue';
import { useFetch } from './useFetch';
export function useUserProfile(userId) {
// 用户基本信息
const { data: user, loading: userLoading } = useFetch(`/api/users/${userId}`);
// 用户帖子列表
const { data: posts, loading: postsLoading } = useFetch(`/api/users/${userId}/posts`);
const loading = ref(true);
const error = ref(null);
onMounted(() => {
Promise.all([user, posts])
.catch(err => error.value = err)
.finally(() => loading.value = false);
});
return { user, posts, loading, error };
}
对于存在依赖关系的异步操作(如先获取用户再获取订单),建议使用 async/await 顺序执行:
export function useOrderHistory(userId) {
const orders = ref([]);
const loading = ref(true);
const error = ref(null);
const fetchOrders = async () => {
try {
// 先获取用户权限
const user = await fetchUser(userId);
if (!user.hasPermission('viewOrder')) return;
// 再获取订单数据
const response = await fetch(`/api/orders?userId=${userId}`);
orders.value = await response.json();
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
};
onMounted(fetchOrders);
return { orders, loading, error };
}
interface FetchResult {
data: Ref;
error: Ref;
loading: Ref;
refetch: () => Promise;
}
export function useFetch(url: string): FetchResult {
// 类型安全的实现...
}
Vue3 Hooks 带来的不仅仅是代码组织方式的变化,更是组件开发思维的升级:
随着 Vue 生态的不断完善,Hooks 正在成为中大型项目开发的标配。建议开发者从简单场景开始实践,逐步掌握:
通过持续沉淀可复用的 Hook 库,团队可以有效提升开发效率,降低维护成本,真正发挥 Composition API 的强大威力。