0%

用React+Antd封装Axios实现全局Loading效果

今天在做 react 后台管理的时候要实现一个全局 Loading 效果,通常使用 axios 库与后端进行数据交互。为了更好的用户体验,在每次请求前添加一个加载效果,让用户知道在等待加载。

前言

要实现这个功能,我们可以在每个组件请求手动添加加载效果返回后再将其隐藏,但如果每个请求都这么做,就要做多次重复设置显得很麻烦,但好处是可以设置定制多种请求效果。但考虑到该项目场景为后台管理系统,给管理员使用,花样可以不用搞太多,统一优雅即可,故采取全局设置 loading 效果。

开发版本

1
2
3
"react": "^16.13.1",
"antd": "^4.0.4",
"axios": "^0.19.2"

代码说明

  1. 通过 axios 提供的请求拦截和响应拦截的接口,控制 loading 的显示或者隐藏。在此我还设置了没有网络和网络超时的提示信息
  2. 采用 antd 的 Spin 组件来实现 loading 效果,message 组件来进行消息提示(antd.css 这里没有引入,是因为我设置了按需加载)
  3. 定义变量 requestCount 作为计数器,确保同一时刻如果有多个请求的话,不会同时添加多个 loading,而是只有 1 个,并在所有请求结束后才会隐藏 loading。
  4. 默认所有请求都会自动有 loading 效果。如果某个请求不需要 loading 效果,可以在请求 headers 中设置 isLoading 为 false。

步骤

  1. 在 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({
// baseURL: process.env.BASE_URL, // 设置请求的base url
timeout: 20000, // 设置超时时长
})

// 设置post请求头
Axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'

// 当前正在请求的数量
let requestCount = 0

// 显示loading
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++
}

// 隐藏loading
function hideLoading() {
requestCount--
if (requestCount === 0) {
document.body.removeChild(document.getElementById('loading'))
}
}

// 请求前拦截
Axios.interceptors.request.use(
config => {
// requestCount为0,才创建loading, 避免重复创建
if (config.headers.isLoading !== false) {
showLoading()
}
return config
},
err => {
// 判断当前请求是否设置了不显示Loading
if (err.config.headers.isLoading !== false) {
hideLoading()
}
return Promise.reject(err)
}
)

// 返回后拦截
Axios.interceptors.response.use(
res => {
// 判断当前请求是否设置了不显示Loading
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
  1. 添加 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;
}
  1. axios 请求
1
2
3
4
5
6
7
8
9
10
// 1. 引入自定义axios文件路径
// 2. 引入共用css文件(loading样式)
// 3. 在react组件中正常写法请求url即可
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)
})

效果

-------------本文结束感谢您的阅读-------------