首页 文章

如何使用Redux Thunk处理fetch()响应中的错误?

提问于
浏览
18

我正在使用isomorphic fetch创建API请求,并使用Redux来处理我的应用程序的状态 .

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

我有以下(工作进行中/坏)代码,但无法找出触发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))
        })
    }
}

如果我无法禁用互联网连接,在JS控制台中,当我通过console.log()(如上所述)登录时,它输出: 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动作(一般错误,一个特定于我们在发生错误时执行的操作) .

我正在努力实现的目标是什么?

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

2 回答

  • 52

    我对几件事感到困惑:

    • 为什么在调度两个同步动作时使用 Promise.all ?使用类似 {type: PRE_FETCH_RESOURCES_FAIL, ...} 的方式调用 dispatch 将不会返回Promise,因此 Promise.all 是不必要的 . Promise.all() 仅在您发送的操作本身被写为thunk动作创建者时才有用,这不是这里的情况 .

    • return dispatch => ... 仅在动作创建者的一开始就是必需的 . 没有必要在 catchthen 块中重复这一点 - 事实上,重复它会使内部代码根本不执行 . 这是一种在顶级函数中注入 dispatch 的方法,没有必要重复它 .

    • 如果在 catch 之后放置 then ,即使在捕获到错误后它也会运行 . 这不是您想要的行为 - 在错误处理程序之后立即运行成功处理程序是没有意义的 . 您希望它们是两个独立的代码路径 .

    • 次要命名挑剔:您将响应称为“ req ” . 应该是 res .

    感觉你有一个关于Redux Thunk如何工作的错误心智模型,并试图将不同示例的部分组合在一起直到它点击 . 随机缩进也有助于此代码有点难以理解 .

    这将是一个痛苦的未来,所以我建议得到一个更完整的心理模型Redux Thunk做什么, return dispatch => ... 的意思,以及Promise如何适应图片 . 我会推荐这个答案为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'})
          }
        );
      }
    }
    
  • -2

    解决方案只是(对于错误记录的两个实例)替换:

    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'})
    ])```
    

    附:

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

相关问题