使用Loader组件拦截所有API请求-React Axios

时间:2019-02-28 20:46:30

标签: javascript reactjs redux axios

我想添加一个在React中进行API调用时要渲染的Loader组件。我的减速器中有一个isFetching标志,现在我可以在基于此道具的组件级别上做到这一点。但是我在全球范围内需要一个。有没有办法做到这一点?

这是我计划使用的implementation

下面是我的dataService:

        //if dev mode them URL prefix = http://127.0.0.1:8080/
    //else
    // prefix= .

    // url= prefix + /users/xyz
    import axios from 'axios';

    const DEV_MODE_URL_PREFIX = '/api/';
    const PROD_MODE_URL_PREFIX = './api/';
    const ENV = process.env.NODE_ENV;

    function getService(relativeUrl, options) {

        return dataService(relativeUrl, options);
    }

    function postService(relativeUrl, dataToPost, options) {
        return dataService(relativeUrl, options, dataToPost);
    }

    function dataService(relativeUrl, options, dataToPost) {
        /**
         * dataToPost = {
         *  key: value
         * } || string
         * options = {
         *  actions: {
         *    requestAction: function ()
         *    successAction: function (response)
         *    failureAction: function (error)
         *  },
         *  shouldRequest: function (state)
         * }
         */
        return (dispatch, getState) => {
            let url;
            const { requestAction, successAction, failureAction } = options.actions;
            if (relativeUrl.match(/json/)) {
                url = relativeUrl;
            } else {
                if (relativeUrl[0] === '/') {
                    relativeUrl = relativeUrl.slice(1);
                }
                if (relativeUrl[relativeUrl.length - 1] !== '/') {
                    relativeUrl += '/';
                }
                if (ENV !== 'production') {
                    url = DEV_MODE_URL_PREFIX + relativeUrl;
                } else {
                    url = PROD_MODE_URL_PREFIX + relativeUrl;
                }
            }

            if (options.shouldRequest(getState())) {
                let promise;
                const data = typeof dataToPost === 'string' ? { 'data': dataToPost } : dataToPost;
                dispatch(requestAction());
                promise = dataToPost ? axios.post(url, data, { withCredentials: true }) : axios.get(url, { withCredentials: true });
                return promise
                    .then(response => {
                        console.log(
                            `status: ${response.status}
                message: ${response.message}`
                        );
                        if (response.status === 200) {
                            return dispatch(successAction(response, dispatch));
                        }
                        return Promise.reject(response);
                    })
                    .catch(error => {
                        console.log(error);
                        return dispatch(failureAction(error));
                    });
            } else {
                return Promise.reject('FETCHING');
            }
        };
    }

    export {
        getService,
        postService
    };

请咨询。

我曾经在Angular中做过这件事,并且想要在React中做同样的事情。

1 个答案:

答案 0 :(得分:1)

您可以在更高级别的组件(例如App)中设置 axios 拦截器。您可以使用“ SHOW_LOADER”和“ HIDE_LOADER”操作类型在减速器中定义加载状态。这些拦截器将在通过 axios 发送和接收请求之前调度相应的操作,从而更新商店中的加载状态,您可以通过该状态来呈现Loader组件。

希望这能回答您的问题。

应用组件

import React from 'react';
import axios from 'axios'
import { connect } from 'react-redux';
import { loading } from '../actions'
import Loader from './Loader'

class App extends React.Component{
 componentWillMount(){
   const self = this
   axios.interceptors.request.use(function (config) {
     // spinning start to show
     self.props.loading(true)
     return config
    }, function (error) {
      return Promise.reject(error);
    });

    axios.interceptors.response.use(function (response) {
     // spinning hide
      self.props.loading(false)

     return response;
   }, function (error) {
     return Promise.reject(error);
   });
 }
 render(){
   return (
    <div>
      { this.props.loader ? <Loader /> : null }

      {/* 
        Your other components
      */}
    </div>
   )
 }

}

const mapStateToProps = (state)=>{
  return {
    loader: state.loader
  }
}

export default connect(mapStateToProps,{
  loading
})(App);

Loader Reducer

const loader = (state = false, action) => {
    switch (action.type) {
        case "SHOW_LOADER":
            return action.data;
            break;
        case "HIDE_LOADER":
            return action.data;
            break;
        default:
            return state;
    }
}

export default loader;

操作

export const loading = (bool)=>{
  return bool ? {
    type:"SHOW_LOADER",
    data:bool
  }: {
    type: "HIDE_LOADER",
    data: bool
  }
}