简单写写和使用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>
相关推荐
weixin_382395232 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__2 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.2 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~3 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华4 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子6 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅6 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni7 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学8 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端