likes
comments
collection
share

Vue3 的Hooks, 即“组合式函数”(Composables) 在项目中的使用

作者站长头像
站长
· 阅读数 25

什么是“组合式函数”?

在 Vue 应用的概念中,“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数。

当构建前端应用时,我们常常需要复用公共任务的逻辑。例如为了在不同地方格式化时间,我们可能会抽取一个可复用的日期格式化函数。这个函数封装了无状态的逻辑:它在接收一些输入后立刻返回所期望的输出。复用无状态逻辑的库有很多,比如你可能已经用过的 lodash 或是 date-fns

相比之下,有状态逻辑负责管理会随时间而变化的状态。一个简单的例子是跟踪当前鼠标在页面中的位置。在实际应用中,也可能是像触摸手势或与数据库的连接状态这样的更复杂的逻辑。

Vuejs 官网抄的简介, 移步官网查看更详细说明 what-is-a-composable

我个人对 VueHooks 的浅薄理解

  1. 是一个以 use 开头命名的函数, 比如 useCount
  2. 该函数内部可以使用 ref, reactive, computed, onMounted 等响应式方法工具或生命周期函数钩子
  3. 该函数会返回具有响应式的变量、函数方法
  4. Hooks 可以在多个不同页面直接导入使用, 就跟一个工具函数差不多
  5. Hooksutils 中的工具函数, 我觉得区别就是返回的变量是否有响应式
  6. Hooks 实际就是把页面的部分代码提取了在一个函数中, 通过导入的方式嵌入的原代码中执行

理解很浅,就这么多吧,哪里写得不对,感谢指出!

初次了解 Hooks

最近用 Vue3 + vant 从零开始做一个移动端的项目, 项目不算大, 但项目1期的开发时间非常紧, 根本没有时间去把代码写得好看一些, 虽然分成了许多组件, 但代码仍然是写得又长又臭, 还有许多重复的代码片段。

项目2期的开发时间宽裕了许多, 就可以多花一些时间把公共的代码提取出去。

一开始搜很多 Hook 相关的文章看, 大部分文章举的例子都是 useAdd, useMouse 之类的例子, 一眼就能看懂了, 但是我项目中用不上这些东西呢? 所以我一开始写出来的 Hooks 是长这样的:

/src/hooks/useState.js

export function useState() {
  const stateList = [
    { value: 0, label: '未提交', color: 'default' },
    { value: 1, label: '审批中', color: 'primary' },
    { value: 2, label: '已驳回', color: 'danger' },
    { value: 3, label: '已撤回', color: 'danger' },
    { value: 4, label: '审批通过', color: 'success' },
    { value: 5, label: '关闭', color: 'default' },
  ];
  const getState = (state) => {
    const item = reimburseState.find((item) => item.value === state);
    return {
      label: item ? item.label : '',
      color: item ? item.color : 'default',
    };
  };
  return {
    stateList,
    getState,
  };
}

list.vue 中使用

<script setup>
import { useState } from '@/hooks/useState';

const { stateList, getState } = useState();
// xxx
</script>

写的时候我心中也有疑问, 这不就是一个普通的 utils 函数吗, 为何叫 Hooks ?

等我把代码写得越来越臭, 我就确认了这确实是一个普通的 utils, 真正的 Hooks 应该是响应式的;

我项目中的 Hooks

我这个移动端的项目中, 有很多个页面都用到了一个部门列表的下拉框, 部门列表的数据需要通过接口请求才拿到, 一开始的写法, 在 A 页面写一遍接口调用, B 页面Ctrl C/V一遍, C页面Ctrl C/V一遍, 需要修改的时候一个个页面去修改, 我又不想把它封装成一个组件(组件间的交互让我觉得有些乏味), 这时候可以使用 Hooks

实现1: 获取部门列表

/hooks/useDepartmentList.js

import { getDepartmentList } from '@/api/common';

export function useDepartmentList() {
  const showPicker = ref(false);
  const departmentList = ref([]);
  const loading = ref(false);
  const getList = async () => {
    loading.value = true;
    const { data } = await getDepartmentList();
    loading.value = false;
    if (data.code === 200) {
      departmentList.value = data.data;
    }
  };
  onMounted(getList);
  return { showPicker, departmentList, loading };
}

A.vue 页面中使用

<template>
    <van-field
        v-model="formState.departmentName"
        name="departmentName"
        is-link
        readonly
        label="所属部门"
        placeholder="请选择所属部门"
        :rules="[{ required: true, message: '请选择所属部门' }]"
        required
        @click="showPicker = true"
    />

    <van-popup v-model:show="showPicker" round position="bottom">
        <van-picker
          :columns="departmentList"
          :loading="loading"
          @cancel="showPicker = false"
          @confirm="onPickerConfirm"
        />
    </van-popup>
</template>
import { useDepartmentList } from '@/hooks/useDepartmentList'; // 导入

const formState = reactive({
    departmentId: '',
    departmentName: '',
});
const { showPicker, departmentList, loading } = useDepartmentList(); // 使用
const onPickerConfirm = ({ selectedOptions }) => {
  // 这个方法逻辑也可以处理到 `useDepartmentList` 函数中
};

实现2: 获取数据统计, 接口需要在页面中调用

/hooks/useCount.js

import { getCountApi } from '@/api/common';

export function useCount() {
  const countValue = ref(0);
  const getCount = async () => {
    const { data } = await getCountApi();
    if (data.code === 200) {
      countValue.value = data.data;
    }
  };
  return { countValue, getCount };
}

A.vue 页面中使用

<template>
    {{ countValue }}
</template>
import { useCount } from '@/hooks/useCount'; // 导入
const { countValue, getCount } = useCount();
onMounted(getCount);

在已缓存的 B.vue 页面中使用

// ...
onActivated(getCount);

结尾

举的例子比较简单, 但我想已经把 Hooks 的用法和与Utils 工具函数的区别写清楚了的。

我目前这个项目中, 写的Hooks代码最多的一个useXxx.js有128行, 共有两个页面使用了这个useXxx.js,相比两个页面都有这么大坨的重复代码, 令我感到非常舒服。

突然想到去年做的那个项目, 好多个页面都重复写了短信验证码相关的一大坨代码, 我得去优化下...

转载自:https://juejin.cn/post/7373955162128203803
评论
请登录