简单写写和使用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>
相关推荐
糕冷小美n1 小时前
elementuivue2表格不覆盖整个表格添加固定属性
前端·javascript·elementui
小哥不太逍遥1 小时前
Technical Report 2024
java·服务器·前端
沐墨染1 小时前
黑词分析与可疑对话挖掘组件的设计与实现
前端·elementui·数据挖掘·数据分析·vue·visual studio code
anOnion2 小时前
构建无障碍组件之Disclosure Pattern
前端·html·交互设计
threerocks2 小时前
前端将死,Agent 永生
前端·人工智能·ai编程
问道飞鱼2 小时前
【前端知识】Vite用法从入门到实战
前端·vite·项目构建
爱上妖精的尾巴3 小时前
8-10 WPS JSA 正则表达式:贪婪匹配
服务器·前端·javascript·正则表达式·wps·jsa
Zhencode3 小时前
Vue3响应式原理之ref篇
vue.js
shadow fish3 小时前
react学习记录(三)
javascript·学习·react.js
小疙瘩4 小时前
element-ui 中 el-upload 多文件一次性上传的实现
javascript·vue.js·ui