【问题标题】:redux-promise with Axios, and how do deal with errors?redux-promise 与 Axios,以及如何处理错误?
【发布时间】:2016-05-28 02:43:25
【问题描述】:

所以,我看到一个错误,redux-promise 将错误返回给我,而且似乎不合适。使用带有 reduc-promise(中间件)的 axios 时,什么是处理错误情况的有效方法..这是我所拥有的要点..

in action/
const request = axios(SOME_URL);

return {
   type: GET_ME_STUFF,
   payload: request
}

in reducer/
  const startState = {
     whatever: [],
     error: false
  }

  case GET_ME_STUFF:
     return {...state, startState, {stuff:action.payload.data, error: action.error? true : false}}

等...然后我可以处理错误..所以,我的 api 调用现在分为两个单独的区域,这似乎是错误的....这里一定有我遗漏的东西。我会认为在 /actions 中我可以传入一个回调来处理新的操作等。或其他东西,但不能拆分它。

【问题讨论】:

    标签: redux axios redux-promise


    【解决方案1】:

    我也经历过类似的情况。挑战在于你可能无法评估 promise 的结果,直到它在 reducer 中。你可以在那里处理你的异常,但这不是最好的模式。根据我的阅读,reducer 仅用于根据 action.type 返回适当的状态片段,不做任何其他事情。

    所以,输入一个额外的中间件 redux-thunk。它不是返回一个对象,而是返回一个函数,并且可以和promise共存。

    http://danmaz74.me/2015/08/19/from-flux-to-redux-async-actions-the-easy-way/ [存档here] 上解释得很好。本质上,您可以在此处评估 promise 并在 promise 结果到达 reducer 之前通过其他 action 创建者进行调度。

    在您的操作文件中,添加可以处理成功和错误(以及任何其他)状态的其他操作创建者。

    function getStuffSuccess(response) {
      return {
        type: GET_ME_STUFF_SUCCESS,
        payload: response
      }
    }
    
    function getStuffError(err) {
      return {
        type: GET_ME_STUFF_ERROR,
        payload: err
      }
    }
    
    export function getStuff() {
      return function(dispatch) {
        axios.get(SOME_URL)
          .then((response) => {
            dispatch(getStuffSuccess(response))
          })
          .catch((err) => {
            dispatch(getStuffError(err))
          })
      }
    }
    
    return null
    

    这大致是您如何将伪代码转换为链接中解释的内容。这处理直接在你的动作创建者中评估承诺,并按照动作 -> 减速器 -> 状态 -> 组件更新周期的约定向你的减速器触发适当的动作和有效负载。我自己对 React/Redux 还是很陌生,但我希望这会有所帮助。

    【讨论】:

    • @FirstOne 我添加了指向 Wayback Machine 存档的链接。
    【解决方案2】:

    接受的答案没有使用 redux-promise。由于问题实际上是关于使用 redux-promise 处理错误,我提供了另一个答案。

    在reducer中你应该检查action对象上是否存在error属性:

    // This is the reducer
    export default function(previousState = null, action) {
      if (action.error) {
        action.type = 'HANDLE_XHR_ERROR'; // change the type
      }  
      switch(action.type) {
        ...
    

    并更改操作的类型,触发您为此设置的错误处理组件的状态更改。

    您可以在 github 上阅读更多相关信息 here

    【讨论】:

    • 这真的很有帮助,也是我现在要使用的路线。请注意,您似乎不应该更改减速器中的操作:redux.js.org/docs/…
    • @freb 是的,你说得有道理。我现在使用 redux-promise-middleware 可以很好地处理错误。
    • 你说得对,redux-promise-middleware 看起来更适合错误处理。谢谢指点!
    • 把它放在你的 switch 语句之外是一个非常糟糕的主意。如果不同的操作有错误怎么办?它还会导致此案例(以及您类似实施的其他案例)执行。
    【解决方案3】:

    看起来您可以在进行分派时捕获错误,然后在发生错误时进行单独的错误分派。这有点小技巧,但确实有效。

      store.dispatch (function (dispatch) {
          dispatch ({
            type:'FOO',
            payload:axios.get(url)
          })
          .catch (function(err) {
            dispatch ({
              type:"FOO" + "_REJECTED",
              payload:err
            });
          });
      });
    

    在减速器中

    const reducer = (state=initialState, action) => {
      switch (action.type) {
        case "FOO_PENDING": {
          return {...state, fetching: true};
        }
        case "FOO_REJECTED": {
          return {...state, fetching: false, error: action.payload};
        }
        case "FOO_FULFILLED": {
          return {
            ...state,
            fetching: false,
            fetched: true,
            data: action.payload,
          };
        }
      }
      return state;
    };
    

    【讨论】:

      【解决方案4】:

      仍然使用 redux-promises,你可以做这样的事情,我认为这是处理这个问题的一种优雅方式。

      首先,将一个属性设置为 redux 状态,该属性将保存可能发生的任何 ajax 错误。

      ajaxError: {},
      

      其次,设置一个reducer来处理ajax错误:

      export default function ajaxErrorsReducer(state = initialState.ajaxError, action) {
        if (action.error) {
          const { response } = action.payload;
          return {
            status: response.status,
            statusText: response.statusText,
            message: response.data.message,
            stack: response.data.stack,
          };
        }
        return state;
      }
      

      最后,创建一个非常简单的 react 组件,如果有任何错误将呈现(我正在使用 react-s-alert 库来显示漂亮的警报):

      import React, { Component } from 'react';
      import { connect } from 'react-redux';
      import PropTypes from 'prop-types';
      import Alert from 'react-s-alert';
      
      class AjaxErrorsHandler extends Component {
      
        constructor(props, context) {
          super(props, context);
          this.STATUS_GATE_WAY_TIMEOUT = 504;
          this.STATUS_SERVICE_UNAVAILABLE = 503;
        }
      
        componentWillReceiveProps(nextProps) {
          if (this.props.ajaxError !== nextProps.ajaxError) {
            this.showErrors(nextProps.ajaxError);
          }
        }
      
        showErrors(ajaxError) {
          if (!ajaxError.status) {
            return;
          }
          Alert.error(this.getErrorComponent(ajaxError), {
            position: 'top-right',
            effect: 'jelly',
            timeout: 'none',
          });
        }
      
        getErrorComponent(ajaxError) {
          let customMessage;
          if (
            ajaxError.status === this.STATUS_GATE_WAY_TIMEOUT ||
            ajaxError.status === this.STATUS_SERVICE_UNAVAILABLE
          ) {
            customMessage = 'The server is unavailable. It will be restored very shortly';
          }
          return (
            <div>
              <h3>{ajaxError.statusText}</h3>
              <h5>{customMessage ? customMessage : ajaxError.message}</h5>
            </div>
          );
        }
      
        render() {
          return (
            <div />
          );
        }
      
      }
      
      AjaxErrorsHandler.defaultProps = {
        ajaxError: {},
      };
      
      AjaxErrorsHandler.propTypes = {
        ajaxError: PropTypes.object.isRequired,
      };
      
      function mapStateToProps(reduxState) {
        return {
          ajaxError: reduxState.ajaxError,
        };
      }
      
      export default connect(mapStateToProps, null)(AjaxErrorsHandler);
      

      你可以在你的 App 组件中包含这个组件。

      【讨论】:

        【解决方案5】:

        这可能不是最好的方法,但它对我有用。我将组件的“this”作为 var 上下文传递。然后,当我得到响应时,我只需执行在我的组件上下文中定义的方法。在我的组件中,我有successHdl 和errorHdl。从那里我可以正常触发更多的 redux 操作。我检查了所有以前的答案,对于这样一个微不足道的任务似乎太艰巨了。

        export function updateJob(payload, context){
        
            const request = axios.put(UPDATE_SOMETHING, payload).then(function (response) {
                context.successHdl(response);
            })
            .catch(function (error) {
                context.errorHdl(error);
            });;
        
            return {
                type: UPDATE_SOMETHING,
                payload: payload,
            }
        }
        

        【讨论】:

          【解决方案6】:

          不要使用 redux-promise。它使您自己做的实际上超级简单的事情变得过于复杂。

          改为阅读 redux 文档:http://redux.js.org/docs/advanced/AsyncActions.html

          它将让您更好地理解如何处理这种交互,并且您将学习如何(比)自己编写一些东西(比)redux-promise。

          【讨论】:

          • 这不是真正的答案。这是主观的,更糟糕​​的是,它没有提供任何信息来支持您的主张。正如你所说,它可能,但如果没有细节,这只是一个简短的咆哮,没有任何可操作性。
          • 这是一个建议,我给出了很好的理由。接受的答案也不使用 redux-promise。我可能应该将其添加为问题的评论而不是答案。没错
          猜你喜欢
          • 2017-08-27
          • 2018-03-09
          • 2019-10-20
          • 2014-03-15
          • 2016-12-12
          • 2016-09-07
          • 1970-01-01
          • 2018-10-02
          相关资源
          最近更新 更多