react路由懒加载loding和异步请求loding

481 阅读3分钟
1.使用 React.lazy 来懒加载页面(进入对应的路由页面才开始加载)节省资源,让响应速度更快。
2.发送异步请求的时候出现loding图标,请求成功之后隐藏loding图片,给用户更好的体验。
3.由于2个loding都是基于antd的 Spin 组件,会存在冲突,所以做了 z-index 的层级处理。

一:页面路由懒加载loding

1:新建 src/components/SpinLoding文件夹

1.1:新建index.tsx

import styles from "./index.module.scss";
import { Spin } from "antd";
import React from "react";
function SpinLoding() {
  return (
    <div className={styles.SpinLoding}>
      <Spin size='large'/>
    </div>
  );
}
const MemoSpinLoding = React.memo(SpinLoding);

export default MemoSpinLoding;

1.2:新建index.module.scss

.SpinLoding {
  position: relative;
  z-index: 9999;
  width: 100%;
  height: 100%;
  background-color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
}

2:在页面中使用

//导入
import { Router, Route, Switch } from "react-router-dom";
import SpinLoding from "./components/SpinLoding";

//懒加载的页面组件
const Layout = React.lazy(() => import("./pages/Layout"));
const Login = React.lazy(() => import("./pages/Login"));

      {/* 关于路由 */}
      <Router>
        <React.Suspense fallback={<SpinLoding />}>
          <Switch>
            <Route path="/login" component={Login} />
            <Route path="/" component={Layout} />
          </Switch>
        </React.Suspense>
      </Router>

二:异步请求loding

1:新建 src/components/AsyncSpinLoding文件夹

1.1:新建index.tsx

import styles from "./index.module.scss";
import { Spin } from "antd";
import React from "react";
function AsyncSpinLoding() {
  return (
    <div id="AsyncSpinLoding" className={styles.AsyncSpinLoding}>
      <Spin size="large" />
    </div>
  );
}

const MemoAsyncSpinLoding = React.memo(AsyncSpinLoding);

export default MemoAsyncSpinLoding;

1.2:新建index.module.scss

.AsyncSpinLoding {
  opacity: 0;
  pointer-events: none;
  transition: all .5s;
  position: fixed;
  z-index: 9998;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  // background-color: rgba(0, 0, 0, .6);
  background-color: transparent;
  :global{
    .ant-spin-spinning{
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%,-50%);
    }
  }
}

2.新建src/utils/http.ts来统一处理请求(基于axios)

import axios from "axios";
import { message } from "antd";
// 请求基地址
export const baseURL =
    //开发环境 基地址 和 打包环境 基地址。一般打包环境都是为空,各位可以自己设置
  process.env.NODE_ENV === "development" ? "后端地址" : "";

// 创建 axios 实例
const http = axios.create({
  baseURL: baseURL,
  timeout: 5000,
});

//发送请求和所有请求都发送完毕的标识
let axajInd = 0;
//拿到loding加载元素
const lodingDom: any = document.querySelector("#AsyncSpinLoding");

// 请求拦截器
http.interceptors.request.use(
  function (config: any) {
    // 发请求前打开加载提示
    lodingDom.style.opacity = 1;
    lodingDom.style.pointerEvents = "auto";
    axajInd++;

    //这里的代码是获取token和在所有请求头中添加token,先注释
    //const { token } = getTokenInfo();
    //if (token) config.headers.token = token;
    
    return config;
  },
  function (err) {
    return Promise.reject(err);
  }
);

//定义一个定时器,防止发送多个请求,没有token的情况下多次执行返回登录页和 message 消息提示问题
let timeId = -1;

// 响应拦截器
http.interceptors.response.use(
  function (response) {
    // 请求回来的关闭加载提示
    axajInd--;
    //所有请求都加载成功之后才隐藏loding
    if (axajInd === 0) {
    //可以使用延时器,让loding不会一闪而过,本人项目不需要这个效果
      // setTimeout(() => {
      lodingDom.style.opacity = 0;
      lodingDom.style.pointerEvents = "none";
      // }, 100);
    }
    //后端返回5001的时候为token失效,可以根据自己的后端返回值来判断
    if (response.data.code === 5001 || response.data.code === 5002) {
        //防抖,先清理定时器,防止200毫秒内多次执行
      clearTimeout(timeId);
      timeId = window.setTimeout(() => {
          //清理token信息,先注释,各位根据业务需求自己处理
        //removeTokenInfo();
        message.warning("登录失效!");
        //跳到登录页,这里使用的是自己封装的history,各位可以自己处理调整逻辑,先注释
        //history.push("/login");
      }, 200);
    } else if (response.data.code === 0) {
        //请求成功,这里不做处理,在对应的业务模块,针对处理
      // message.success(response.data.msg);
    } else message.warning(response.data.msg); //请求失败,返回后端的失败信息
    return response.data;
  },
  async function (err) {
      //在请求失败的时候,直接把 axajInd 标识归0,防止loding一直存在
    axajInd = 0;
    // setTimeout(() => {
    lodingDom.style.opacity = 0;
    lodingDom.style.pointerEvents = "none";
    // }, 300);
    // 如果因为网络原因,response没有,给提示消息
    if (!err.response) {
      message.warning("网络繁忙,请稍后重试!");
    } else {
      message.warning("错误!");
    }

    return Promise.reject(err);
  }
);

// 导出 axios 实例
export default http;

3.在页面中使用,这里我在App根组件中使用,全局都可以拿到这个加载的dom

在src/App.tsx中

    //导入
    import AsyncSpinLoding from "./components/AsyncSpinLoding";
    //使用
      {/* 发送请求的加载组件 */}
      <AsyncSpinLoding />