react+redux+antd 实现 loading 全局设置使用详细详细!

文章目录

  • 前言
    • 在 redux 中添加方法
    • 哪里用到 包 哪里
    • 封装请求与响应
    • 使用


前言

最近在做的一个项目使用的是 react + redux + antd,有一个需求是需要在发送请求时,出现遮罩层,当数据请求成功后,遮罩层消失。由于项目有很多组件,每一个组件也会有很多请求接口。在每次请求的时候设置属性控制遮罩层的显示自然是可以实现,但是这样对于一个前端来说一点都不优美,而且在项目中必定会出现很多接口同时请求的,那这不就更复杂了!!!

当然,我们必须做一个优美的前端工程师啦!于是,根据自己的想法和在网上查了一些资料。我决定,使用 antd 的 spin 组件的延迟效果,加上 redux 实现全局设置。


在 redux 中添加方法

  • 添加的方法有两个:打开 loading 和关闭 loading
  • 在 action.js 中
//开启loading
export const openLoading =  ()=>({
    type:OPENLOADING,
})

//关闭loading
export const closeLoading =  ()=>({
    type:CLOSELOADING,
})
  • 在 actionType.js 中
export const OPENLOADING = "openLoading"
export const CLOSELOADING = "closeLoading"
  • 在 reducers.js 中
import { OPENLOADING, CLOSELOADING } from "./actionType";

let defaultState = {
  loading:false,
};

export function todoReducer(state = defaultState, action) {
  let newObj = { ...state };
  switch (action.type) {
    case OPENLOADING: {
      newObj.loading = true;
      return newObj;
    }
    case CLOSELOADING: {
      newObj.loading = false;
      return newObj;
    }
    default:
      return state;
  }
}

温馨提示:如果对以上步骤不清楚明白的,可以先提前了解 redux 的使用,这是基础的 redux 使用方法

哪里用到 包 哪里

这个意思就是,哪些组件需要用到,我们就把 spin 组件包住它。是不是好像还是没有说清楚,好的,我就用我现在的项目举一个例子吧!
项目中,登录页并不需要使用 loading,而是在登陆成功之后到达的页面开始全需要在请求时使用 loading。
如下图,我的 XXX 组件中包含了我需要用到 loading 的组件路由:

import { store } from '../../redux/store.js'
import { Spin } from 'antd'

export default class XXX extends Component {

  state = {
    loading: false
}
componentDidMount () {
  // 注册(订阅)监听, 一旦状态发生改变, 自动重新渲染
  store.subscribe(() => {
    this.setState({
      loading: store.getState().loading
    })
  })
}
 
  render() {
    return (
      <Spin spinning={this.state.loading}>
        <Route ... />
        ...
        <Route ... />
      </Spin>
    );
  }
}

没错就是这么简单,这一步完成之后就差不多完成一半了,接下来也是最重要的另一半。

封装请求与响应

在项目中,我使用到的是 axios

  • 新建一个 axios.js 文件,需要写三个东西:

1、一个计数器:正如前言所说的,有很多请求是同时发起的,但是结束就不一定一起结束了,这时候我们需要在请求都结束之后,才能取消 loading
2、请求的拦截:需要在发起请求时,打开 loading ; 请求超时,关闭 loading
3、响应的拦截:得到响应时,关闭 loading

import axios from "axios";
import { message } from "antd";
import { store } from "../../redux/store";
import { openLoading, closeLoading } from "../../redux/actions";

let Axios = axios.create({
  // timeout: 5000
});

// 计数器
let requestCount = 0;

// 展示 loading
function showLoading() {
  if (requestCount === 0) {
    store.dispatch(openLoading());
  }
  requestCount++;
}

// 隐藏 loading
function hideLoading() {
  if (requestCount <= 0) return;
  requestCount--;
  if (requestCount === 0) {
    store.dispatch(closeLoading());
  }
}

// 删除 isLoading 字段  // 特别强调!!! 看下文
function deleteLoading(obj) {
  let newObj = { ...obj };
  delete newObj.isLoading;
  return newObj;
}

// 请求拦截
Axios.interceptors.request.use(
  (config) => {
    if (config.isLoading !== false) {
      showLoading();
    }
    return deleteLoading(config);
  },
  (error) => {
    if (error.isLoading !== false) {
      hideLoading();
    }
    message.error("请求超时");
    return Promise.reject(deleteLoading(error));
  }
);

// 响应拦截
Axios.interceptors.response.use(
  (response) => {
    if (response.config.isLoading !== false) {
      hideLoading();
    }
    let { data } = response;
    if (data.code === 0) {
      return data;
    }
  },
  (error) => {
    if (error.config.isLoading !== false) {
      hideLoading();
    }
    message.error("服务错误");
    return Promise.reject(error);
  }
);

export default Axios;

  • 新建一个 http.js 文件,封装 axios
import axios from 'axios';
import {store} from "../../redux/store"
import Axios from "./axios.js"
const http={}

/**
 * GET
 * @param {*} url 
 * @param {*} data 
 * @param {*} isLoading true:使用遮罩层  false:不使用
 * @returns 
 */
http.get = (url, data,isLoading=true) => {
  return Axios({
      method: 'get',
      url: url,
      params: data,
      isLoading: isLoading,   // 特别强调!!! 看下文
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${store.getState().token}`,
      },
    })
};

/**
 * POST
 * @param {*} url 
 * @param {*} data 
 * @param {*} isLoading true:使用遮罩层  false:不使用
 * @returns 
 */
http.post = (url, data, isLoading=true) => {
  return Axios({
      method: 'post',
      url: url,
      data: data,
      isLoading: isLoading,
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${store.getState().token}`,
      },
  })
};

特别强调!!!
以上两处特别强调是相关联的,因为在我的需求中,组件中的有些请求是不需要使用 loading 的,所以我会在封装 axios 中自定义添加一个属性 isloading 来判断是否需要使用 loading, 判断之后我会将这个自定义的属性删除,如果后端在不知情的情况下没有做配置,服务器会不承认你自定义的这个字段,会导致说出现一些报错等情况,所以,我就干脆在我需要这个字段的时候使用它,不需要它了我就它删除!

使用

  • 需要使用 loading
import http from "../../server/http";
import api from "../../server/interface";  //接口文档

http.get(api, data).then((res) => {
      console.log(res.data);
    });
  • 不需要使用 loading
import http from "../../server/http";
import api from "../../server/interface";  //接口文档

http.get(api, data,false).then((res) => {
      console.log(res.data);
    });

这样就完成了 loading 全局设置使用!

你可能感兴趣的:(reactjs)