如何使用 Redux Thunk 处理 fetch() 响应中的错误? [英] How to handle errors in fetch() responses with Redux Thunk?

查看:16
本文介绍了如何使用 Redux Thunk 处理 fetch() 响应中的错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用同构获取发出 API 请求,并使用 Redux 来处理我的应用程序的状态.

I'm making API requests using isomorphic fetch, and using Redux to handle my app's state.

我想通过触发 Redux 操作来处理互联网连接丢失错误和 API 错误.

I want to handle both internet connection loss errors, and API errors, by firing off Redux actions.

我有以下(正在进行的/错误的)代码,但无法找出触发 Redux 操作的正确方法(而不仅仅是抛出错误并停止一切):

I have the following (work-in-progress / bad) code, but can't figure out the correct way to fire the Redux actions (rather than just throw an error and stop everything) :

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))
        })
    }
}

如果我故意禁用互联网连接,在 JS 控制台中,当我通过 console.log()(如上)登录时,它会输出:<代码>POST http://example.com/post net::ERR_INTERNET_DISCONNECTED(匿名函数)(派遣) {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(...)

If I intionally disable the internet connection, in the JS Console, when I log via console.log() (as above), it's outputting this: 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(…)

如果这是完全错误的,请原谅我,但我不想做任何事情,只是在出现错误时触发两个 Redux 操作(一个一般错误,一个特定于发生错误时我们正在执行的操作).

Forgive me if this is entirely wrong, but I don't want to do anything but fire off two Redux Actions when there is an error (a general error, and one specific to the action we were performing when the error occurred).

我正在努力实现的目标是可能的吗?

Is what I'm trying to achieve even possible?

似乎(通过我的控制台登录)脚本的then"部分仍在执行(因为它的内容是我的catch"调度函数)..

It seems that (via my logging to console) the 'then' part of the script is still being executed (as the contents of it are my 'catch' dispatch functions)..

推荐答案

我对几件事感到困惑:

  1. 为什么要使用 Promise.all 来分派两个同步操作?使用诸如 {type: PRE_FETCH_RESOURCES_FAIL, ...} 之类的东西调用 dispatch 不会返回 Promise,因此 Promise.all 是不必要的.Promise.all() 仅当您发送的操作自己被编写为 thunk 操作创建者时才有用,而这里的情况并非如此.
  2. 返回调度=>... 在动作创建者的最开始只需要一次.无需在 catchthen 块中重复此操作——事实上,重复它会使内部代码根本无法执行.这是一种将 dispatch 注入顶层函数的方法,没有必要重复.
  3. 如果你把 then 放在 catch 之后,它会在错误被捕获后运行.这不是您想要的行为——在错误处理程序之后立即运行成功处理程序是没有意义的.您希望它们是两个独立的代码路径.
  4. 次要命名挑剔:您将响应称为req".它可能应该是 res.
  1. Why do you use Promise.all around dispatching two synchronous actions? Calling dispatch with something like {type: PRE_FETCH_RESOURCES_FAIL, ...} won’t return a Promise, so Promise.all is unnecessary. Promise.all() is only useful if the actions you dispatch are themselves written as thunk action creators, which is not the case here.
  2. return dispatch => ... is only necessary once at the very beginning of the action creators. There is no need to repeat this in the catch or then blocks—in fact, repeating it makes the inner code not execute at all. This is a way to inject dispatch into your function at the top level, and there is no point to repeating it.
  3. If you put then after a catch, it will run even after an error was caught. This is not the behavior your want—it doesn’t make sense to run the success handler right after the error handler. You want them to be two separate code paths.
  4. Minor naming nitpick: you are calling the response a "req". It should probably be res.

感觉就像你对 Redux Thunk 的工作方式有一个错误的心理模型,并且正在尝试将不同示例的部分组合在一起直到它点击.随机缩进也导致这段代码有点难以理解.

It feels like you have a wrong mental model of how Redux Thunk works, and are trying to combine parts of different examples together until it clicks. The random indentation also contributes to this code being a little bit hard to understand.

这在未来会很痛苦,所以我建议对 Redux Thunk 所做的事情有一个更完整的心理模型,return dispatch =>... 意味着,以及 Promise 是如何融入图片的.我会推荐这个答案作为 深入Redux Thunk 简介.

This is going to be painful in the future so instead I suggest to get a more complete mental model of what Redux Thunk does, what return dispatch => ... means, and how Promises fit into the picture. I would recommend this answer as an in-depth introduction to Redux Thunk.

如果我们解决了这些问题,您的代码应该大致如下:

If we fix those problems, your code should look roughly like this instead:

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'})
      }
    );
  }
}

这篇关于如何使用 Redux Thunk 处理 fetch() 响应中的错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆