1. 什么是 Hook
- 定义:Hook 是一种特殊的函数,它封装了具有状态的逻辑,使得代码可以复用。在 Vue 和 React 等现代前端框架中,Hook 允许开发者在组件之间共享状态逻辑。
- 来源:Hook 概念源自 React,Vue 3 引入了类似的组合式 API。
- 区别:Hook 函数与普通函数的区别在于 Hook 可以包含状态(响应式变量)。
2. 在 Vue 中使用 Hook
- 目的:提高代码的可维护性和复用性。
- 自定义 Hook 示例:
// mouse.js import { ref, onMounted, onUnmounted } from 'vue'; export function useMouse() { const x = ref(0); const y = ref(0); function update(event) { x.value = event.pageX; y.value = event.pageY; } onMounted(() => window.addEventListener('mousemove', update)); onUnmounted(() => window.removeEventListener('mousemove', update)); return { x, y }; } - 使用社区提供的 Hook:
import { useMouse } from 'VueUse';
3. 封装自定义 Hook
- 场景分析:封装用于表格数据获取和分页的 Hook。
- 封装 useTable:
// useTable.ts import { ref, reactive } from 'vue'; export function useTable(api) { const data = ref([]); const refresh = () => api().then(res => data.value = res); refresh(); return [data, refresh]; } - 封装 usePagination:
// usePagination.ts import { reactive } from 'vue'; export function usePagination(cb, sizeOption = [10, 20, 50, 100, 200]) { const pagination = reactive({ current: 1, total: 0, sizeOption, size: sizeOption[0], onPageChange(page, extraData) { pagination.current = page; return extraData ? cb(extraData) : cb(); }, onSizeChange(size, extraData) { pagination.current = 1; pagination.size = size; return extraData ? cb(extraData) : cb(); }, setTotal(total) { pagination.total = total; }, reset() { pagination.current = 1; pagination.total = 0; pagination.size = pagination.sizeOption[0]; }, }); return [pagination, pagination.onPageChange, pagination.onSizeChange, pagination.setTotal]; }
4. 封装技巧
- 返回值:自定义 Hook 可以返回数组或对象。
- 异步处理:在 Hook 中使用
then而不是await处理异步请求。
5. 支持不同接口字段
- 参数处理:允许自定义 Hook 接受参数,以适应不同的 API 需求。
- 示例:
export function useTable(api, params = {}, options = {}) { const [pagination, , , setTotal] = usePagination(() => refresh()); const data = ref([]); const refresh = (extraData = {}) => { const requestData = { [options.path.page]: pagination.current, [options.path.size]: pagination.size, ...params, ...extraData, }; return api(requestData).then((res) => { data.value = get(res, options.path.data, []); setTotal(get(res, options.path.total, 0)); }); }; options.immediate && refresh(); return [data, refresh, pagination]; }
6. 总结
- Hook 提供了一种强大的方式,用于在 Vue 和 React 等框架中封装和复用状态逻辑。
- 自定义 Hook 可以帮助开发者编写更优雅、更可维护的代码。
- 通过封装和参数化,Hook 可以适应各种不同的业务场景和 API 需求。