vue3 hook的使用

摘要

vue3 中的 hooks就是函数的一种写法,就是将文件的一些单独功能的js代码进行抽离出来,放到单独的js文件中,或者说是一些可以复用的公共方法/功能。其实hooks 和 vue2 中的 mixin 有点类似,但是相对 mixins 而言, hooks 更清楚复用功能代码的来源, 更清晰易懂。

用hook改造组件

字典选择下拉框
<script setup name="DDemo" lang="ts">
  import { onMounted, ref } from 'vue';

  //   模拟调用接口
  function getRemoteData() {
    return new Promise<any[]>((resolve) => {
      setTimeout(() => {
        resolve([
          {
            key: 1,
            name: '苹果',
            value: 1,
          },
          {
            key: 2,
            name: '香蕉',
            value: 2,
          },
          {
            key: 3,
            name: '橘子',
            value: 3,
          },
        ]);
      }, 3000);
    });
  }
  
  const optionsArr = ref<any[]>([]);

  onMounted(() => {
    getRemoteData().then((data) => {
      optionsArr.value = data;
    });
  });
</script>

<template>
  <div>
    <a-select :options="optionsArr" />
  </div>
</template>

<style lang="less" scoped></style>

看起来很简单是吧,忽略我们模拟调用接口的代码,我们用在ts/js部分的代码才只有6行而已,看起来根本不需要什么封装。

如果我们把所有的意外情况都考虑到的话,代码就会变得很臃肿了。

<script setup name="DDemo" lang="ts">
  import { onMounted, ref } from 'vue';

  //   模拟调用接口
  function getRemoteData() {
    return new Promise<any[]>((resolve, reject) => {
      setTimeout(() => {
        // 模拟接口调用有概率出错
        if (Math.random() > 0.5) {
          resolve([
            {
              key: 1,
              name: '苹果',
              value: 1,
            },
            {
              key: 2,
              name: '香蕉',
              value: 2,
            },
            {
              key: 3,
              name: '橘子',
              value: 3,
            },
          ]);
        } else {
          reject(new Error('不小心出错了!'));
        }
      }, 3000);
    });
  }

  const optLoading = ref(false);
  const optionsArr = ref<any[]>([]);

  function initSelect() {
    optLoading.value = true;
    getRemoteData()
      .then((data) => {
        optionsArr.value = data;
      })
      .catch((e) => {
        // 请求出线错误时将错误信息显示到select中,给用户一个友好的提示
        optionsArr.value = [
          {
            key: -1,
            value: -1,
            label: e.message,
            disabled: true,
          },
        ];
      })
      .finally(() => {
        optLoading.value = false;
      });
  }

  onMounted(() => {
    initSelect();
  });
</script>

<template>
  <div>
    <a-select :loading="optLoading" :options="optionsArr" />
  </div>
</template>

代码直接来到了22行,虽说用户体验确实好了不少

封装下拉框hook
import { onMounted, reactive, ref } from 'vue';
// 定义下拉框接收的数据格式
export interface SelectOption {
  value: string;
  label: string;
  disabled?: boolean;
  key?: string;
}
// 定义入参格式
interface FetchSelectProps {
  apiFun: () => Promise<any[]>;
}

export function useFetchSelect(props: FetchSelectProps) {
  const { apiFun } = props;

  const options = ref<SelectOption[]>([]);

  const loading = ref(false);

  /* 调用接口请求数据 */
  const loadData = () => {
    loading.value = true;
    options.value = [];
    return apiFun().then(
      (data) => {
        loading.value = false;
        options.value = data;
        return data;
      },
      (err) => {
        // 未知错误,可能是代码抛出的错误,或是网络错误
        loading.value = false;
        options.value = [
          {
            value: '-1',
            label: err.message,
            disabled: true,
          },
        ];
        // 接着抛出错误
        return Promise.reject(err);
      }
    );
  };

  //   onMounted 中调用接口
  onMounted(() => {
    loadData();
  });

  return reactive({
    options,
    loading,
  });
}

在组件中调用

<script setup name="DDemo" lang="ts">
  import { useFetchSelect } from './hook';

  //   模拟调用接口
  function getRemoteData() {
    return new Promise<any[]>((resolve, reject) => {
      setTimeout(() => {
        // 模拟接口调用有概率出错
        if (Math.random() > 0.5) {
          resolve([
            {
              key: 1,
              name: '苹果',
              value: 1,
            },
            {
              key: 2,
              name: '香蕉',
              value: 2,
            },
            {
              key: 3,
              name: '橘子',
              value: 3,
            },
          ]);
        } else {
          reject(new Error('不小心出错了!'));
        }
      }, 3000);
    });
  }
   
   // 将之前用的 options,loading,和调用接口的逻辑都抽离到hook中
  const selectBind = useFetchSelect({
    apiFun: getRemoteData,
  });
</script>

<template>
  <div>
    <!-- 将hook返回的接口,通过 v-bind 绑定给组件 -->
    <a-select v-bind="selectBind" />
  </div>
</template>

代码行数直接又从20行降到3

总结

日常开发任务中的一次案例分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zqwang888

一毛不嫌少,一块不嫌多!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值