简单写写和使用useRequest-vue版

在以往的业务项目中,我们经常会被 loading 状态的管理等重复的功能实现所困扰。每次开启一个新项目都需要重新实现一遍,这是一项重复的工作。

VueRequest 的目的是为开发人员提供一种方便、快速的方式来管理 API 状态。通过简单的配置,可以省去那些繁琐的任务,专注于业务核心的开发。

官网地址

以下是我自己简单实现的,当练练手了。

使用 - 一开始就请求数据

js 复制代码
const request_apiStatisticsFormat = () => apiStatisticsFormat({ schoolId, groupCode, groupType });

const { data, loading, error, run } = useRequest(request_apiStatisticsFormat, {
  ready: true,
  deps: [],
  isShowLoading: true,
  onSuccess: (res) => {
    console.log('res', res);
    studentList.value = res.data.studentList;
  },
});

api的相关方法

ts 复制代码
export const apiGetStudentList = (params: IParams) =>
  get<ResponseData>(`/k12-app-api/api/npad/homeSchool/interact/getStudentList`, {
    params,
    // baseURL: 'https://ntteacher-api-test1.test.xdf.cn',
  });
export const apiStatisticsFormat = (params: IParams) => formatApiFn(apiGetStudentList, params, mockData);

export interface ResponseData<T = any> {
  data: T;
  status?: string | number;
  code?: string | number;
  msg: string;
  success: boolean;
}

export const formatApiFn = async (
  apiFn: (params?: any) => Promise<any>,
  params: any,
  mockData?: any,
) => {
  try {
    const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time));
    mockData && (await sleep(1000));
    const res = mockData ? mockData : await apiFn(params);
    const { data } = res;
    if (data.success) return data;
    return Promise.reject(data);
  } catch (error) {
    return Promise.reject(error);
  }
};

使用 - 等特定条件才开始请求数据

ts 复制代码
const { data, loading, error, run } = useRequest(request_apiStatisticsFormat, {
  // ready取决于isSelectedDate
  ready: isSelectedDate.value,
  // date值一旦发生变化,就重新请求数据
  deps: [date],
  isShowLoading: true,
  onSuccess: (res) => {
    console.log('res', res);
    const {
      connectStudentList: connectStudentListData,
      notConnectStudentList: notConnectStudentListData,
      statistics: statisticsData,
    } = res.data || {};
  },
});

useRequest

ts 复制代码
import { ref, watch } from 'vue';
import { Toast } from 'vant';
import Vue from 'vue';
Vue.use(Toast);
interface IUseRequestOptions {
  // 请求成功回调
  onSuccess?: (data: any) => void;
  // 请求错误回调
  onError?: (error: any) => void;
  // 请求结束回调
  onFinally?: () => void;
  // 是否自动执行,默认是true
  ready?: boolean;
  // 监听依赖项,自动执行
  deps?: any[];
  // 初始data值
  initialData?: any;
  // 是否展示加载效果
  isShowLoading?: boolean;
}

export const useRequest = (
  requestFn: (requestParams?: any) => Promise<any>,
  options?: IUseRequestOptions,
) => {
  // 初始值
  const data = ref(options?.initialData);
  // loading 是否正在请求
  const loading = ref(false);
  // error 是否请求错误
  const error = ref(null);
  const { onSuccess, onError, onFinally, ready, deps, isShowLoading } = options || {
    ready: true,
  };
  // run就是请求函数
  const run = async () => {
    error.value = null;
    // 正在请求中
    loading.value = true;
    console.log('开始', 1);
    try {
      // 请求函数
      const res = await requestFn();
      // 请求结果赋值
      data.value = res;
      console.log('成功', res);
      error.value = null;
      // 请求成功回调
      onSuccess && onSuccess(res);
    } catch (err) {
      console.log('错误', err);
      // 请求错误赋值
      error.value = err;
      // 请求错误回调
      onError && onError(err);
    } finally {
      // 请求结束
      loading.value = false;
      // 请求结束回调
      onFinally && onFinally();
    }
  };
  // 是否展示加载效果
  isShowLoading &&
    watch(loading, (newVal) => {
      newVal
        ? Toast.loading({
            message: '加载中...',
            forbidClick: true,
          })
        : Toast.clear();
    });
  // 如果ready为true,自动执行
  ready && run();
  // 监听依赖项,自动执行
  watch(deps, () => {
    run();
  });

  return {
    data,
    loading,
    error,
    run,
  };
};

错误状态显示

vue 复制代码
<!-- 使用     
https://blog-huahua.oss-cn-beijing.aliyuncs.com/blog/code/error_3.png
https://blog-huahua.oss-cn-beijing.aliyuncs.com/blog/code/empty3.png

<StatusPage v-if="error" text="网络错误,请稍候再试~" :showLoadBtn="true" @reload="run" :isFullScreen="true"/>

<StatusPage v-if="isEmpty" text="暂无数据~" :isFullScreen="true" />

局部空数据展示
<div v-if="isEmpty" style="height: 300px; position: relative" >
  <StatusPage :isFullScreen="false" text="暂无数据~" />
</div>
 -->
<template>
  <div class="status-page-box" :class="{isFullScreen}">
    <div class="empty-error-page" id="pageError">
      <img class="img" src="@/assets/images/error.png" />
      <div class="des">{{ text }}</div>
      <div v-if="showLoadBtn" class="btn-load" @click="$emit('reload')">重新加载</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { defineProps } from 'vue';
const props = defineProps({
  text: {
    type: String,
  },
  isFullScreen: {
    type: Boolean,
    default: true,
  },
  showLoadBtn: {
    type: Boolean,
    default: false,
  },
});
</script>

<style scoped lang="less">
.isFullScreen{
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background: #fafafa;
  z-index: 888888;
}
.empty-error-page {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 8;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  text-align: center;
  .img {
    width: 102px;
    height: 97px;
  }
  .des {
    font-size: 14px;
    color: #999;
  }
  .btn-load {
    font-size: 14px;
    font-weight: 500;
    color: #ffffff;
    line-height: 34px;

    width: 100px;
    height: 34px;
    background: linear-gradient(180deg, #49d391 0%, #34d0aa 100%);
    border-radius: 17px;
    text-align: center;
    margin-top: 20px;
  }
}
</style>
相关推荐
万少3 分钟前
万少用9个AI工具,帮朋友完成了一个"不可能"的项目
前端
小小小小宇5 分钟前
Vue `import` 为什么可以异步加载
前端
WMYeah11 分钟前
【无标题】
前端·rust·抽奖程序·跨平台抽奖程序
Unbelievabletobe11 分钟前
免费外汇api的响应时间在不同时段下的波动分析
大数据·开发语言·前端·python
大哥,带带弟弟21 分钟前
Grafana 前端嵌入与 JWT 鉴权实战
前端·grafana
小小小小宇22 分钟前
前端 V8 引擎垃圾回收机制与内存问题排查
前端
前端老石人33 分钟前
CSS 值定义语法
前端·css
sheeta199843 分钟前
Vue 前端基础笔记
前端·vue.js·笔记
小小小小宇43 分钟前
GitLab + GitLab Runner + Qiankun 微前端 + Nginx + Node 中间件 前端开发机从零搭建 CI/CD 全流程
前端
前端那点事1 小时前
别再写垃圾组件!Vue3 如何设计「真正可复用」的高质量通用组件
前端·vue.js