美文网首页
vue3 Loading状态hook 自用

vue3 Loading状态hook 自用

作者: 很好就这样吧 | 来源:发表于2023-04-12 19:05 被阅读0次
// hook.ts
import { Ref, ref } from 'vue';

type TApiFun<TData, TParams extends Array<any>> = (...params: TParams) => Promise<TData>;

interface AutoRequestOptions {
   // 定义一下初始状态
  loading?: boolean;
  // 接口调用成功时的回调
  onSuccess?: (data: any) => void;
}

type AutoRequestResult<TData, TParams extends Array<any>> = [Ref<boolean>, TApiFun<TData, TParams>];

/* 控制loading状态的自动切换hook */
export function useAutoRequest<TData, TParams extends any[] = any[]>(fun: TApiFun<TData, TParams>, options?: AutoRequestOptions): AutoRequestResult<TData, TParams> {
  const { loading = false, onSuccess } = options || { loading: false };

  const requestLoading = ref(loading);

  const run: TApiFun<TData, TParams> = (...params) => {
    requestLoading.value = true;
    return fun(...params)
      .then((res) => {
        onSuccess && onSuccess(res);
        return res;
      })
      .finally(() => {
        requestLoading.value = false;
      });
  };

  return [requestLoading, run];
}


// api/index.ts
export function submitApi(text: string) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // 模拟接口调用有概率出错
      if (Math.random() > 0.5) {
        resolve({
          status: "ok",
          text: text,
        });
      } else {
        reject(new Error("不小心出错了!"));
      }
    }, 3000);
  });
}


// index.vue
<script setup name="Index" lang="ts">
import { useAutoRequest } from "./hook";
import { Button } from "ant-design-vue";
import { submitApi } from "@/api";

const [loading, submit] = useAutoRequest(submitApi);

function onSubmit() {
   submit("aaa").then((res) => {
    console.log("res", res);
  });
}
</script>

<template>
  <div class="col">
    <Button :loading="loading" @click="onSubmit">提交</Button>
  </div>
</template>


这个hook还有另一种玩法:

// hook2.ts
import type { Ref } from "vue";
import { ref } from "vue";

type AutoLoadingResult = [
  Ref<boolean>,
  <T>(requestPromise: Promise<T>) => Promise<T>
];

/* 在给run方法传入一个promise,会在promise执行前或执行后将loading状态设为true,在执行完成后设为false */
export function useAutoLoading(defaultLoading = false): AutoLoadingResult {
  const ld = ref(defaultLoading);

  function run<T>(requestPromise: Promise<T>): Promise<T> {
    ld.value = true;
    return requestPromise.finally(() => {
      ld.value = false;
    });
  }

  return [ld, run];
}


// index.vue
<script setup name="Index" lang="ts">
// import { useAutoRequest } from "./hook";
import { useAutoLoading } from "./hook2";
import { Button } from "ant-design-vue";
import { submitApi, cancelApi } from "@/api";

// const [loading, submit] = useAutoRequest(submitApi);

const [commonLoading, fetch] = useAutoLoading();

function onSubmit() {
  fetch(submitApi("submit")).then((res) => {
    console.log("res", res);
  });
}

function onCancel() {
  fetch(cancelApi("cancel")).then((res) => {
    console.log("res", res);
  });
}
</script>

<template>
  <div class="col">
    <Button type="primary" :loading="commonLoading" @click="onSubmit">
      提交
    </Button>
    <Button :loading="commonLoading" @click="onCancel">取消</Button>
  </div>
</template>


这里也是用到了promise链式调用的特性,在接口调用之后马上将loading置为true,在接口调用完成后置为false。而useAutoRequest则是在接口调用之前就将loading置为true。
useAutoRequest调用时代码更简洁,useAutoLoading的使用则更灵活,可以同时服务给多个接口使用,比较适合提交、取消这种互斥的场景。

摘抄来源

作者:背对疾风
链接:https://juejin.cn/post/7181712900094951483
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关文章

网友评论

      本文标题:vue3 Loading状态hook 自用

      本文链接:https://www.haomeiwen.com/subject/xymgddtx.html