更优雅得使用 useLoading Hook 实现请求加载状态管理

512 阅读3分钟

简介

在现代前端开发中,处理异步请求的加载状态是提升用户体验的重要环节。用户在等待数据加载时,提供一个清晰的反馈可以显著减少不确定性和焦虑感。本文将介绍一个简单而有效的 Vue 3 Hook——useLoading,它能够帮助开发者轻松管理加载状态。

背景介绍

在单页应用(SPA)中,用户与应用的交互通常涉及到多个异步请求,例如 API 调用、数据获取等。为了提升用户体验,开发者需要在请求发出时显示加载状态,并在请求完成后隐藏加载状态。传统的做法通常需要在每个请求中手动管理加载状态,这样不仅繁琐,而且容易出错。

useLoading Hook 的出现正是为了解决这个问题。它通过封装加载状态管理的逻辑,使得开发者可以专注于业务逻辑,而无需重复编写加载状态的管理代码。

而我们此次 useLoading 封装,不仅使用方便,而且适配 传统 Promise 处理以及 async/await 使用模式,更加灵活方便。

使用指南

安装

确保你已经在项目中安装了 Vue 3。然后可以直接将 useLoading.ts 文件放入你的 hooks 目录中。

示例代码

在你的 Vue 组件中使用 useLoading Hook,如下所示:

<template>
    <div v-loading="loading"></div>
</template>

<script lang='ts' setup>
import { useLoading } from '@/hooks';
import { DataApi } from '@/api'; // 假设你有一个数据 API

const { loading, loadingWrapper } = useLoading();

/**
* 请求数据的方法 async/await
*/
const queryDataList = async () => {
    const res = await loadingWrapper(DataApi.queryData({})
    // ... 处理数据
}

/**
* 请求数据的方法 Promise.then
*/
const queryDataList = () => {
    loadingWrapper(DataApi.queryData({}).then(res => {
        let data = res.data.data.list;
        // ... 处理数据
    }));
}

</script>

有朋友可能会问,我同一个文件中有多个请求怎么办,不用担心,忘了 ts/js 支持模块重命名了吗? 我们可以如下操作:

<template>
  <div v-loading="loading"></div>
  <div v-loading="loadingDelete"></div>
</template>

<script lang="ts" setup>
import { useLoading } from "@/hooks";
import { DataApiAdd, DataApiDelete } from "@/api"; // 假设你有一个数据 API
/**
 * 多个请求
 * 请求数据的方法 async/await
 */
const { loading, loadingWrapper } = useLoading();

const queryDataAdd = async () => {
  const res = await loadingWrapper(DataApiAdd.queryData({}));
  // ... 处理数据
};

const { loading: loadingDelete, loadingWrapper: loadingWrapperDelete } = useLoading();

const queryDataDelete = async () => {
  const res = await loadingWrapperDelete(DataApiDelete.queryData({}));
  // ... 处理数据
};
</script>

源码

完整代码

import { ref, computed } from "vue";
export default function useLoading() {
  /**
   * 使用number类型的loadingIndex
   * 更适用于多个请求的场景
   */
  const loadingIndex = ref(0);
  /**
   * 计算属性,根据loadingIndex的值判断
   * @returns boolean
   */
  //
  const loading = computed(() => {
    return loadingIndex.value <= 0 ? false : true;
  });
  // 进入loading,loadingIndex的值加1
  const enterLoading = () => {
    loadingIndex.value += 1;
  };
  /**
   * 退出loading,loadingIndex的值减1
   */
  const quitLoading = () => {
    if (loadingIndex.value > 0) {
      loadingIndex.value -= 1;
    } else {
      console.warn("no need quit loading");
    }
  };

  /**
   * 包装请求,自动完成进入/退出loading的设置
   * @param promise - 需要包装的Promise
   * @returns 返回包装后的Promise
   */
  const loadingWrapper = <T>(promise: Promise<T>) => {
    return new Promise<T>((resolve, reject) => {
      // 进入loading
      enterLoading();
      promise
        .then((result) => {
          resolve(result);
        })
        .catch((error) => {
          reject(error);
        })
        .finally(() => {
          // 退出loading
          quitLoading();
        });
    });
  };
  return {
    loading,
    enterLoading,
    quitLoading,
    loadingWrapper,
  };
}
适用范围

useLoading Hook 适用于需要对多个异步请求进行加载状态管理的场景。它可以用于:

  • API 数据请求
  • 文件上传/下载
  • 任何需要异步操作的场景

总结

useLoading Hook 是一个简单而强大的工具,可以帮助开发者高效地管理加载状态,提升用户体验。通过封装复杂的状态管理逻辑,开发者可以专注于业务逻辑,从而提高开发效率。希望本文能帮助你更好地理解和使用 useLoading Hook!

好了,今天的内容就到分享这里啦,很享受与大家一起学习,沟通交流问题,如果喜欢的话,请为我来个3连吧 !👍 (为爱发电,点点小手,您的点赞收藏是我更新的动力!)

作者:ChenUvi

邮箱: chenui@outlook.com