今天在做 react 后台管理的时候要实现一个全局 Loading 效果,通常使用 axios 库与后端进行数据交互。为了更好的用户体验,在每次请求前添加一个加载效果,让用户知道在等待加载。
前言
要实现这个功能,我们可以在每个组件请求手动添加加载效果返回后再将其隐藏,但如果每个请求都这么做,就要做多次重复设置显得很麻烦,但好处是可以设置定制多种请求效果。但考虑到该项目场景为后台管理系统,给管理员使用,花样可以不用搞太多,统一优雅即可,故采取全局设置 loading 效果。
开发版本
1 2 3
   | "react": "^16.13.1", "antd": "^4.0.4", "axios": "^0.19.2"
   | 
代码说明
- 通过 axios 提供的请求拦截和响应拦截的接口,控制 loading 的显示或者隐藏。在此我还设置了没有网络和网络超时的提示信息
 - 采用 antd 的 Spin 组件来实现 loading 效果,message 组件来进行消息提示(antd.css 这里没有引入,是因为我设置了按需加载)
 - 定义变量 requestCount 作为计数器,确保同一时刻如果有多个请求的话,不会同时添加多个 loading,而是只有 1 个,并在所有请求结束后才会隐藏 loading。
 - 默认所有请求都会自动有 loading 效果。如果某个请求不需要 loading 效果,可以在请求 headers 中设置 isLoading 为 false。
 
步骤
- 在 src 目录下新建一个文件 axios.js
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
   | import axios from 'axios' import React, { Component } from 'react' import ReactDOM from 'react-dom' import { message, Spin } from 'antd'
  const Axios = axios.create({      timeout: 20000,  })
 
  Axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
 
  let requestCount = 0
 
  function showLoading() {   if (requestCount === 0) {     var dom = document.createElement('div')     dom.setAttribute('id', 'loading')     document.body.appendChild(dom)     ReactDOM.render(<Spin tip='加载中...' size='large' />, dom)   }   requestCount++ }
 
  function hideLoading() {   requestCount--   if (requestCount === 0) {     document.body.removeChild(document.getElementById('loading'))   } }
 
  Axios.interceptors.request.use(   config => {          if (config.headers.isLoading !== false) {       showLoading()     }     return config   },   err => {          if (err.config.headers.isLoading !== false) {       hideLoading()     }     return Promise.reject(err)   } )
 
  Axios.interceptors.response.use(   res => {          if (res.config.headers.isLoading !== false) {       hideLoading()     }     return res   },   err => {     if (err.config.headers.isLoading !== false) {       hideLoading()     }     if (err.message === 'Network Error') {       message.warning('网络连接异常!')     }     if (err.code === 'ECONNABORTED') {       message.warning('请求超时,请重试')     }     return Promise.reject(err)   } )
 
  Component.prototype.$axios = Axios
  export default Axios
   | 
- 添加 loading 样式在共用的 css 文件里
 
1 2 3 4 5 6 7 8 9 10 11 12 13
   | #loading {   position: absolute;   top: 0;   left: 0;   right: 0;   bottom: 0;   background: rgba(0, 0, 0, 0.75);   display: flex;   align-items: center;   justify-content: center;   z-index: 9999;   font-size: 20px; }
  | 
- axios 请求
 
1 2 3 4 5 6 7 8 9 10
   | 
 
  componentDidMount () {     axios({       url: '/manage/statistic/base_count.do'     }).then(res => {       this.setState(res.data)     }) }
 
  | 
不加 loading 效果,这样写
1 2 3 4 5 6 7 8
   | axios({   url: '/manage/statistic/base_count.do',   headers: {     isLoading: false,   }, }).then(res => {   this.setState(res.data) })
  | 
效果
