今天在做 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) })
|
效果