だから、私はエラーを見て、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では、新しいアクションなどを処理するコールバックを渡すことができると思いますが、分割はしません。
私も同じような状況を経験しなければなりませんでした。課題は、おそらく、レジューサーになるまで、プロミスの結果を評価できないことです。あなたはそこで例外を処理できますが、それは最良のパターンではありません。私が読んだものから、レデューサーは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にかなり慣れていませんが、これが役に立てば幸いです。
受け入れられた回答は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 を参照してください。
まだ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コンポーネントに含めることができます。
ディスパッチを行う場所でエラーをキャッチし、それが発生した場合は別のエラーディスパッチを行うことができるようです。これは少しハックですが、機能します。
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;
};
これは最善の方法ではないかもしれませんが、私にとってはうまくいきます。コンポーネントの '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,
}
}