2016-05-06 17 views
15

私はisomorphic fetchを使ってAPIリクエストを行い、Reduxを使ってアプリケーションの状態を処理しています。Redux Thunkでfetch()応答のエラーを処理する方法は?

インターネット接続の切断エラーとAPIエラーの両方を、Reduxのアクションを実行して処理したいと考えています。

私は、次の(作業中の/悪い)コードを持っていますが、(単にすべてをエラーをスローし、停止ではなく)Reduxのアクションを発射するための正しい方法を見つけ出すことはできません。

export function createPost(data = {}) { 

    return dispatch => { 

     dispatch(requestCreatePost(data)) 

     return fetch(API_URL + data.type, { 
      credentials: 'same-origin', 
      method: 'post', 
      headers: { 
       'Accept': 'application/json', 
       'Content-Type': 'application/json', 
       'X-WP-Nonce': API.nonce 
      }, 
      body: JSON.stringify(Object.assign({}, data, {status: 'publish'})) 
     }).catch((err) => { 

      //HANDLE WHEN HTTP ISN'T EVEN WORKING 
      return dispatch => Promise.all([ 
       dispatch({type: PRE_FETCH_RESOURCES_FAIL, errorType: 'fatal', message:'Error fetching resources', id: h.uniqueId()}), 
       dispatch({type: PRE_CREATE_API_ENTITY_ERROR, errorType: 'fatal', id: h.uniqueId(), message: 'Entity error before creating'}) 
      ]) 
     }).then((req) => { 

      //HANDLE RESPONSES THAT CONSTITUTE AN ERROR (VIA THEIR HTTP STATUS CODE) 
      console.log(req); 
      if (!req || req.status >= 400) { 
       return dispatch => Promise.all([ 
        dispatch({type: FETCH_RESOURCES_FAIL, errorType: 'warning', message:'Error after fetching resources', id: h.uniqueId()}), 
        dispatch({type: CREATE_API_ENTITY_ERROR, errorType: 'warning', id: h.uniqueId(), message: 'Entity error whilst creating'}) 
       ]) 
      } 
      else { 
       return req.json() 
      } 
     }).then((json) => { 
      var returnData = Object.assign({},json,{ 
       type: data.type 
      }); 
      dispatch(receiveCreatePost(returnData)) 
     }) 
    } 
} 

私は経由にconsole.log(ログインしたときに、私はintionally(上記のように))、JSコンソールで、インターネット接続を無効にした場合、それはこれを出力しています: POST http://example.com/post net::ERR_INTERNET_DISCONNECTED(anonymous function) (dispatch) { return Promise.all([dispatch({ type: PRE_FETCH_RESOURCES_FAIL, errorType: 'fatal', message: 'Error fetching resources', id: _CBUtils2.default.uniqueId() }), dispatch({ type:… cb_app_scripts.js?ver=1.0.0:27976 Uncaught (in promise) TypeError: req.json is not a function(…)

これは完全に間違っている場合は、私を許し、私ドンエラーが発生した場合は2つのReduxアクションを実行します(一般的なエラーです。エラーが発生したときに再実行)。

達成しようとしていることはありますか?

(私のログを経由してコンソールへの)スクリプトの「を」の部分がまだ実行されている(これの内容は私の「キャッチ」ディスパッチ機能であるとして)。..

答えて

48

:付き

return dispatch => Promise.all([ 
    dispatch({type: PRE_FETCH_RESOURCES_FAIL, errorType: 'fatal', message:'Error fetching resources', id: h.uniqueId()}), 
    dispatch({type: PRE_CREATE_API_ENTITY_ERROR, errorType: 'fatal', id: h.uniqueId(), message: 'Entity error before creating'}) 
])``` 

:(エラーログの両方のインスタンスの)に置き換える

  1. Promise.allなぜ2つの同期アクションをディスパッチするのですか? {type: PRE_FETCH_RESOURCES_FAIL, ...}のようなものをdispatchと呼び出すとPromiseが返されないので、Promise.allは不要です。 Promise.all()は、あなたが送信するアクションが自身である場合はがサンクアクションクリエイターとして記述されている場合にのみ役に立ちます。
  2. return dispatch => ...は、アクションクリエイターの初めに1回だけ必要です。 catchまたはthenブロックでこれを繰り返す必要はありません。実際には、それを繰り返すと、内部コードがまったく実行されなくなります。これは、最上位の関数にdispatchを注入する方法であり、繰り返す必要はありません。
  3. catchの後にthenを入力すると、エラーが検出された後でも実行されます。これは、あなたが望む動作ではありません。エラーハンドラの直後に成功ハンドラを実行するのは意味がありません。それらを2つのコードパスにする必要があります。
  4. 軽度のニックネーム:あなたは応答を "req"と呼んでいます。おそらくresになるはずです。

Redux Thunkの仕組みが間違っていると感じて、クリックするまでさまざまな例の部分を一緒に組み合わせようとしています。ランダムな字下げは、このコードを少し理解するのにも役立ちます。

これは将来的には痛いので、代わりに、Redux Thunkが何をするのか、より具体的にはどのような意味で、どのようにプロミスが絵にフィットするかについて、より完全な精神モデルを得ることをお勧めします。この回答をin-depth introduction to Redux Thunkとしてお勧めします。

我々はこれらの問題を解決する場合は、あなたのコードではなく、おおよそ次のようになります。

export function createPost(data = {}) { 
    return dispatch => { 
    dispatch(requestCreatePost(data)); 

    return fetch(API_URL + data.type, { 
     credentials: 'same-origin', 
     method: 'post', 
     headers: { 
     'Accept': 'application/json', 
     'Content-Type': 'application/json', 
     'X-WP-Nonce': API.nonce 
     }, 
     body: JSON.stringify(Object.assign({}, data, {status: 'publish'})) 
    }) 
    // Try to parse the response 
    .then(response => 
     response.json().then(json => ({ 
     status: response.status, 
     json 
     }) 
    )) 
    .then(
     // Both fetching and parsing succeeded! 
     ({ status, json }) => { 
     if (status >= 400) { 
      // Status looks bad 
      dispatch({type: FETCH_RESOURCES_FAIL, errorType: 'warning', message:'Error after fetching resources', id: h.uniqueId()}), 
      dispatch({type: CREATE_API_ENTITY_ERROR, errorType: 'warning', id: h.uniqueId(), message: 'Entity error whilst creating'}) 
     } else { 
      // Status looks good 
      var returnData = Object.assign({}, json, { 
       type: data.type 
      }); 
      dispatch(receiveCreatePost(returnData)) 
     } 
     }, 
     // Either fetching or parsing failed! 
     err => { 
     dispatch({type: PRE_FETCH_RESOURCES_FAIL, errorType: 'fatal', message:'Error fetching resources', id: h.uniqueId()}), 
     dispatch({type: PRE_CREATE_API_ENTITY_ERROR, errorType: 'fatal', id: h.uniqueId(), message: 'Entity error before creating'}) 
     } 
    ); 
    } 
} 
+1

うわー、詳しい解剖に感謝します。今すぐRedux Thunkのイントロを読んでください。どうもありがとう! –

+0

@ダン・アブラモフどのような場合に、「フェッチが完全に失敗した(corsまたは接続のタ​​イムアウト/拒否)」キャッチといっしょに別の場所にフェッチを抽出したいのですが、そのアクションに特定のキャッチを残してください。出来ますか? –

+0

@ダン・アブラモフ - 私はこのシナリオで約束を守る問題を抱えています。拒否された関数の代わりにチェーン内の解決された関数を常に起動しています。私のエラーアクションがディスパッチされてから間違いなく拒否されたときです。思考? –

-1

ソリューションは、単にだったようです私はいくつかのことについて困惑している

return Promise.all([ 
    dispatch({type: PRE_FETCH_RESOURCES_FAIL, errorType: 'fatal', message:'Error fetching resources', id: h.uniqueId()}), 
    dispatch({type: PRE_CREATE_API_ENTITY_ERROR, errorType: 'fatal', id: h.uniqueId(), message: 'Entity error before creating'}), 
Promise.reject(err) 
]) 
+1

は 'Promise.all'と' Promise.reject'はどちらも不要です。技術的にはそれを機能させることができますが、これはコードが必要以上に複雑になり、目的を果たせなくなります。詳細と書き直しの提案については私の答えを見てください。 –

関連する問題