web-dev-qa-db-ja.com

Axiosでredux-promise、そしてエラーをどうやって処理するのですか?

だから、私はエラーを見て、redux-promiseがエラーを返します:ペイロードと一緒にtrueですが、それはリデューサーに到達すると...リクエストとエラー条件の分離は少し奇妙で、不適切。 axios w/reduc-promise(ミドルウェア)を使用するときにエラー状態に対処する効果的な方法は何ですか。ここに私が持っているものの要点があります。

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呼び出しは2つの別々の領域に分割されており、それは間違っているようです...ここに欠けているものがあるはずです。/actionsでは、新しいアクションなどを処理するコールバックを渡すことができると思いますが、分割はしません。

10
james emanon

私も同じような状況を経験しなければなりませんでした。課題は、おそらく、レジューサーになるまで、プロミスの結果を評価できないことです。あなたはそこで例外を処理できますが、それは最良のパターンではありません。私が読んだものから、レデューサーはaction.typeに基づいて適切な状態の部分を返すことのみを目的としており、他には何もしません。

したがって、追加のミドルウェアredux-thunkを入力します。オブジェクトを返す代わりに、関数を返し、promiseと共存できます。

http://danmaz74.me/2015/08/19/from-flux-to-redux-async-actions-the-easy-way/ [archived ここに] 。基本的に、ここでプロミスを評価し、プロミスの結果がレデューサーに到達する前に、他のアクションクリエーターを通じてディスパッチできます。

アクションファイルに、成功とエラー(およびその他)の状態を処理する追加のアクション作成者を追加します。

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にかなり慣れていませんが、これが役に立てば幸いです。

21
Victor

受け入れられた回答はredux-promiseを利用していません。問題は実際にはredux-promiseを使用してエラーを処理することに関するものなので、別の答えを提供します。

レデューサーでは、アクションオブジェクトのエラー属性の存在を検査する必要があります。

// 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 を参照してください。

11
pors

まだredux-promiseを使用すると、このようなことを行うことができます。これは、この問題に対処するためのエレガントな方法だと思います。

まず、発生した可能性のあるajaxエラーを保持するプロパティをredux状態に設定します。

ajaxError: {},

次に、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ライブラリを使用して、Niceアラートを表示しています)。

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コンポーネントに含めることができます。

1
juank11memphis

ディスパッチを行う場所でエラーをキャッチし、それが発生した場合は別のエラーディスパッチを行うことができるようです。これは少しハックですが、機能します。

  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;
};
1
bruce

これは最善の方法ではないかもしれませんが、私にとってはうまくいきます。コンポーネントの '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,
    }
}
0
Roberto Aguilar