react+ant.d添加全局loading方式

 更新时间:2024年01月24日 15:20:54   作者:土豆Coder  
这篇文章主要介绍了react+ant.d添加全局loading方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

背景

先上个应景图,哈哈哈!

本篇博客中的方法也是前两天刚接触redux时给了我的一点启发,可以从这里着手来实现这个功能。而且,事实证明,确实满足了我的需求。

项目开发中往往需要在接口返回较慢的时候给出loading状态,防止在接口返回值的过程中用户多次点击,之前我们在Vue中也添加过这个功能,而且还在其中遇到过由于单例模式出现的问题,以及如何解决这个问题大家可以自行百度。

Vue中全局loading组件直接通过创建实例的方式,在ant.d中我们的Spin组件需要包裹想要遮罩的元素,我们如何在请求接口的入口统一添加全局loading呢?

这里我们就用到了reduxreact+redux超简单入门实例这里可以带你迅速了解并使用redux

使用redux实现全局Loading

添加Spin

首先在main文件中添加全局Spinmain.js文件包裹了所有菜单栏所包含的内容(除了登录页,基本都包含在这里)

// main.js
import React, { Component } from 'react'
import AppMenu from '../../components/app-menu'
import AppBreadCrum from '../../components/app-breadcrum'
import { Switch, Route } from 'react-router-dom'
import { mainRoutes } from '../../router'
import { Spin } from 'antd'
import store from '../../store'

class Main extends Component {
	state = {
	    loading: false
	}
  render () {
    const { layout, ...rest } = this.props
    let { loading } = this.state
    return (
      <Spin spinning={loading} wrapperClassName="page-loading">
        <div className="main">
          <AppMenu {...rest}></AppMenu>
          <div className="app-right">
            <AppBreadCrum {...rest}></AppBreadCrum>
            <div className="app-bottom">
              <Switch>
                {mainRoutes.map(route => (<Route exact key={route.path} path={route.path} component={route.component}></Route>))}
              </Switch>
            </div>
          </div>
        </div>
      </Spin>
    )
  }
}

export default Main

接口拦截设置Loading显示

我们需要在接口发出请求的时候设置Loading显示,在返回以后设置其为隐藏。

actions

定义两个action动作,一个用来打开loading一个用来关闭loading

// actions/index.js
export const OPENPAGELOADING = 'OpenPageLoading'
export const CLOSEPAGELOADING = 'ClosePageLoading'

reducers

通过不同事件来触发值的改变

// reducers/index.js
import { OPENPAGELOADING, CLOSEPAGELOADING } from '../actions'
const initState = {
  pageLoadingVal: false
}
const AppReducer = (state=initState, action) => {
  switch (action.type) {
    case OpenPageLoading: {
      return {
        pageLoadingVal: true
      }
    }
    case ClosePageLoading: {
      return {
        pageLoadingVal: false
      }
    }
    default: {
      return state
    }
  }
}

export default AppReducer

store

// store/index.js
import { createStore } from 'redux'
import AppReducer from '../reducers'

const store = createStore(AppReducer)

export default store

引入

// index.js
...
import store from './store'

ReactDOM.render(
  <Provider store={store}>
    <ConfigProvider locale={antdZhCn}>
      <Router>
        <App />
      </Router>
    </ConfigProvider>
  </Provider>,
  document.getElementById('root')
)

http.js

接口入口文件中设置全局的值

import axios from 'axios'
import { message } from 'antd'
import store from '../store'
import { OPENPAGELOADING, CLOSEPAGELOADING } from '../actions'

let instance = axios.create({
  baseURL: '',
  timeout: 5000
})

/* 请求拦截 */
instance.interceptors.request.use(config => {
  store.dispatch({type: OPENPAGELOADING})
  return config
}, error => {
  store.dispatch({type: CLOSEPAGELOADING })
  message.error('请求超时')
  return Promise.reject(error)
})

/* 响应拦截 */
instance.interceptors.response.use(response => {
  store.dispatch({type: CLOSEPAGELOADING })
  let { data } = response
  if (data && data.code && data.code === 200) {
    return data
  } else if (data && data.code && data.code === 500) {
    message.error(data.msg || '获取接口数据错误')
    return Promise.reject()
  }
}, error => {
  store.dispatch({type: CLOSEPAGELOADING })
  message.error('服务错误')
  return Promise.reject(error)
})

export default instance

在发出接口请求的时候通过store.dispatch({type: 'OpenPageLoading'})派发操作

需要注意的时候,在无论接口返回是什么的情况下需要通过store.dispatch({type: 'ClosePageLoading'})来关闭loading

监测store中loading值设置是否显示Spin

到此为止我们store中的全局loading的值已经发生了满足需求的改变,

下面要做的就是在每次值发生改变的时候我们能在使用Spin的地方监听到,

说到监听是不是就想到了store提供的subscribe方法呢?怎么做呢?

// main.js
import React, { Component } from 'react'
import AppMenu from '../../components/app-menu'
import AppBreadCrum from '../../components/app-breadcrum'
import { Switch, Route } from 'react-router-dom'
import { mainRoutes } from '../../router'
import { Spin } from 'antd'
import store from '../../store'

class Main extends Component {
	state = {
    	loading: false
	}
  componentDidMount () {
  	// 重点
  	// 重点
  	// 重点
  	// 监听store中pageLoadingVal值
    store.subscribe(() => {
      let storeState = store.getState()
      this.setState({
        loading: storeState.pageLoadingVal
      })
    })
  }
  render () {
    const { layout, ...rest } = this.props
    let { loading } = this.state
    return (
      <Spin spinning={loading} wrapperClassName="page-loading">
        // ...
      </Spin>
    )
  }
}

export default Main

是的,通过监听来设置当前组件的state的值。

优化

如果你一个页面只有一个接口,那么你完成上述就搞定了。

但是,如果你一个页面有多个接口,当其中有个接口返回值很慢的时候你就会发现问题,就是当一个接口pending结束全局loading就消失了,这个当然不是我们想要的结果,理想的亚子是当前页面所有接口都pending结束后才消失loading

这个问题之前在做elementUI+Vue做全局loading时候也遇到过,其实思路是一样的,思路可参考elementUI全局Loading单例模式

因为创建全局loading的方式不同,所以这里思路一样,代码稍有不同

// http.js

import axios from 'axios'
import { message } from 'antd'
import store from '../store'
import { OPENPAGELOADING, CLOSEPAGELOADING } from '../actions'

let instance = axios.create({
  baseURL: '',
  timeout: 5000
})

/* 添加一个计数器 */
let needLoadingRequestCount = 0

function showFullScreenLoading () {
  if (needLoadingRequestCount === 0) {
    store.dispatch({type: OPENPAGELOADING})
  }
  needLoadingRequestCount++
}

function tryHideFullScreenLoading () {
  if (needLoadingRequestCount <= 0) return
  needLoadingRequestCount--
  if (needLoadingRequestCount === 0) {
    store.dispatch({type: CLOSEPAGELOADING})
  }
}

/* 请求拦截 */
instance.interceptors.request.use(config => {
  showFullScreenLoading()
  return config
}, error => {
  tryHideFullScreenLoading()
  message.error('请求超时')
  return Promise.reject(error)
})

/* 响应拦截 */
instance.interceptors.response.use(response => {
  tryHideFullScreenLoading()
  let { data } = response
  if (data && data.code && data.code === 200) {
    return data
  } else if (data && data.code && data.code === 500) {
    message.error(data.msg || '获取接口数据错误')
    return Promise.reject()
  }
}, error => {
  tryHideFullScreenLoading()
  message.error('服务错误')
  return Promise.reject(error)
})

export default instance

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持程序员之家。

相关文章

  • react拖拽组件react-sortable-hoc的使用

    react拖拽组件react-sortable-hoc的使用

    本文主要介绍了react拖拽组件react-sortable-hoc的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • 详解使用WebPack搭建React开发环境

    详解使用WebPack搭建React开发环境

    这篇文章主要介绍了详解使用WebPack搭建React开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • 利用React高阶组件实现一个面包屑导航的示例

    利用React高阶组件实现一个面包屑导航的示例

    这篇文章主要介绍了利用React高阶组件实现一个面包屑导航的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • react 路由Link配置详解

    react 路由Link配置详解

    本文主要介绍了react 路由Link配置详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • React中的Context应用场景分析

    React中的Context应用场景分析

    这篇文章主要介绍了React中的Context应用场景分析,Context 提供了一种在组件之间共享数据的方式,而不必显式地通过组件树的逐层传递 props,通过实例代码给大家介绍使用步骤,感兴趣的朋友跟随小编一起看看吧
    2021-06-06
  • React路由组件传参的三种方式(params、search、state)

    React路由组件传参的三种方式(params、search、state)

    本文主要介绍了React路由组件传参的三种方式,主要包括了params、search、state,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • React DnD如何处理拖拽详解

    React DnD如何处理拖拽详解

    这篇文章主要为大家介绍了React DnD如何处理拖拽示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • React JSX基础语法教程示例

    React JSX基础语法教程示例

    这篇文章主要为大家介绍了React JSX基础语法教程示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • 在create-react-app中使用sass的方法示例

    在create-react-app中使用sass的方法示例

    这篇文章主要介绍了在create-react-app中使用sass的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-10-10
  • React中classnames库使用示例

    React中classnames库使用示例

    这篇文章主要为大家介绍了React中classnames库使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10

最新评论

?


http://www.vxiaotou.com