react+ant.d添加全局loading方式
背景
先上個應(yīng)景圖,哈哈哈!
本篇博客中的方法也是前兩天剛接觸redux
時給了我的一點啟發(fā),可以從這里著手來實現(xiàn)這個功能。而且,事實證明,確實滿足了我的需求。
項目開發(fā)中往往需要在接口返回較慢的時候給出loading
狀態(tài),防止在接口返回值的過程中用戶多次點擊,之前我們在Vue
中也添加過這個功能,而且還在其中遇到過由于單例模式出現(xiàn)的問題,以及如何解決這個問題大家可以自行百度。
Vue
中全局loading
組件直接通過創(chuàng)建實例的方式,在ant.d
中我們的Spin
組件需要包裹想要遮罩的元素,我們?nèi)绾卧谡埱蠼涌诘娜肟诮y(tǒng)一添加全局loading
呢?
這里我們就用到了redux
(react+redux超簡單入門實例這里可以帶你迅速了解并使用redux
)
使用redux實現(xiàn)全局Loading
添加Spin
首先在main
文件中添加全局Spin
,main.js
文件包裹了所有菜單欄所包含的內(nèi)容(除了登錄頁,基本都包含在這里)
// 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
接口攔截設(shè)置Loading顯示
我們需要在接口發(fā)出請求的時候設(shè)置Loading
顯示,在返回以后設(shè)置其為隱藏。
actions
定義兩個action
動作,一個用來打開loading
一個用來關(guān)閉loading
// actions/index.js export const OPENPAGELOADING = 'OpenPageLoading' export const CLOSEPAGELOADING = 'ClosePageLoading'
reducers
通過不同事件來觸發(fā)值的改變
// 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
接口入口文件中設(shè)置全局的值
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) }) /* 響應(yīng)攔截 */ 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 || '獲取接口數(shù)據(jù)錯誤') return Promise.reject() } }, error => { store.dispatch({type: CLOSEPAGELOADING }) message.error('服務(wù)錯誤') return Promise.reject(error) }) export default instance
在發(fā)出接口請求的時候通過store.dispatch({type: 'OpenPageLoading'})
派發(fā)操作
需要注意的時候,在無論接口返回是什么的情況下需要通過store.dispatch({type: 'ClosePageLoading'})
來關(guān)閉loading
。
監(jiān)測store中l(wèi)oading值設(shè)置是否顯示Spin
到此為止我們store
中的全局loading
的值已經(jīng)發(fā)生了滿足需求的改變,
下面要做的就是在每次值發(fā)生改變的時候我們能在使用Spin
的地方監(jiān)聽到,
說到監(jiān)聽是不是就想到了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 () { // 重點 // 重點 // 重點 // 監(jiān)聽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
是的,通過監(jiān)聽來設(shè)置當(dāng)前組件的state
的值。
優(yōu)化
如果你一個頁面只有一個接口,那么你完成上述就搞定了。
但是,如果你一個頁面有多個接口,當(dāng)其中有個接口返回值很慢的時候你就會發(fā)現(xiàn)問題,就是當(dāng)一個接口pending
結(jié)束全局loading
就消失了,這個當(dāng)然不是我們想要的結(jié)果,理想的亞子是當(dāng)前頁面所有接口都pending
結(jié)束后才消失loading
。
這個問題之前在做elementUI+Vue
做全局loading
時候也遇到過,其實思路是一樣的,思路可參考elementUI全局Loading單例模式。
因為創(chuàng)建全局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 }) /* 添加一個計數(shù)器 */ 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) }) /* 響應(yīng)攔截 */ 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 || '獲取接口數(shù)據(jù)錯誤') return Promise.reject() } }, error => { tryHideFullScreenLoading() message.error('服務(wù)錯誤') return Promise.reject(error) }) export default instance
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解關(guān)于React-Router4.0跳轉(zhuǎn)不置頂解決方案
這篇文章主要介紹了詳解關(guān)于React-Router4.0跳轉(zhuǎn)不置頂解決案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05React使用useEffect解決setState副作用詳解
這篇文章主要為大家介紹了React使用useEffect解決setState副作用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10React如何實現(xiàn)瀏覽器打印部分內(nèi)容詳析
這篇文章主要給大家介紹了關(guān)于利用React如何實現(xiàn)瀏覽器打印部分內(nèi)容的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用React具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05使用React Native創(chuàng)建以太坊錢包實現(xiàn)轉(zhuǎn)賬等功能
這篇文章主要介紹了使用React Native創(chuàng)建以太坊錢包,實現(xiàn)轉(zhuǎn)賬等功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07react native實現(xiàn)往服務(wù)器上傳網(wǎng)絡(luò)圖片的實例
下面小編就為大家?guī)硪黄猺eact native實現(xiàn)往服務(wù)器上傳網(wǎng)絡(luò)圖片的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08