redux-thunk和调度结果内部的异常处理

Mat*_*one 7 asynchronous promise reactjs redux redux-thunk

我有一个基于Redux文档的基本的thunk动作创建者和减速器:http : //redux.js.org/docs/advanced/AsyncActions.html

// action creator

function fetchPosts () {
  return dispatch => {
    dispatch({ type: 'FETCH_POSTS_REQUEST' })

    return fetch('http://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(json => dispatch({ type: 'FETCH_POSTS_SUCCESS', items: json }))
      // THIS CATCHES FETCH REQUEST ERRORS, AND COMPONENT LEVEL ERRORS
      .catch(error => dispatch({ type: 'FETCH_POSTS_FAILURE', error: error.message }))
  }
}

// reducer

function reducer (state = { isFetching: false, items: [] }, action) {
  switch (action.type) {
    case 'FETCH_POSTS_REQUEST':
      return Object.assign({}, state, { isFetching: true })
    case 'FETCH_POSTS_SUCCESS':
      return Object.assign({}, state, { isFetching: false, items: action.items })
    case 'FETCH_POSTS_FAILURE':
      return Object.assign({}, state, { isFetching: false })
    default:
      return state
  }
}
Run Code Online (Sandbox Code Playgroud)

在以状态传递为道具的React组件中,我检查发布项的存在,如果存在则强制执行组件级错误:

const Test = props => {
  if (!props.items.length) return null
  throw new Error('Error!')
}
Run Code Online (Sandbox Code Playgroud)

启动应用程序时:

  1. fetchPosts 动作创建者称为
  2. 发出HTTP请求,并在响应之后调度FETCH_POSTS_SUCCESS操作。
  3. 现在,组件会更新状态中的结果,并尝试读取props.invalidProperty.error
  4. 这会导致JS异常: Cannot read property 'error' of undefined

到目前为止,一切都很好。

问题是该组件的JS异常永远不会输出到控制台。取而代之的是,catch()用于获取承诺的块会捕获错误,并调度一个FETCH_POSTS_FAILURE操作。

这样可以吞下受更新存储影响的组件中的所有错误。一个FETCH_POSTS_FAILURE状态变化被分派,但这种感觉不正确-没有错误实际上获取的职位,但在使用这些职位的分量的误差下游。

我正在寻找一种模式,以帮助将异步请求中的错误与通过调度更改状态而发生的任何其他随机错误区分开。


编辑:

Redux github回购中带有异步示例的示例:https : //github.com/nandastone/redux/commit/88ab48040ce41c39d8daba8cc0c13a6f32c38adf#diff-eeb827d44ad03655e63b7e9319a03dd4R6

c.P*_*.u1 7

一个Promise.catch处理程序还可以捕获来自该决议或拒绝处理出现的任何错误。

fetch('http://jsonplaceholder.typicode.com/posts').then(res => {
  throw new Error();
}).catch(err => {
  //will handle errors from both the fetch call and the error from the resolution handler
});
Run Code Online (Sandbox Code Playgroud)

要仅处理来自的错误fetch并确保dispatch({ type: 'FETCH_POSTS_SUCCESS', items: json })解析处理程序中的调用引发的任何错误均未捕获到该catch处理程序中,请将拒绝处理程序附加到fetch

return fetch('http://jsonplaceholder.typicode.com/posts').then(response => response.json, error => {
    dispatch({ type: 'FETCH_POSTS_FAILURE', error: error.message });
}).then(json => dispatch({ type: 'FETCH_POSTS_SUCCESS', items: json }), error => {
    //response body couldn't be parsed as JSON
});
Run Code Online (Sandbox Code Playgroud)

fetch 不会将状态代码> = 400视为错误,因此仅在出现网络或CORS错误时才会拒绝上述调用,这就是为什么必须在解析处理程序中检查状态代码的原因。

function fetchHandler(res) {
  if (res.status >= 400 && res.status < 600) {
    return Promise.reject(res);
  }
  return res.json();
}



return fetch('http://jsonplaceholder.typicode.com/posts').then(fetchHandler, error => {
    //network error
    dispatch({ type: 'NETWORK_FAILURE', error });
}).then(json => dispatch({ type: 'FETCH_POSTS_SUCCESS', items: json }), error => {
    dispatch({ type: 'FETCH_POSTS_FAILURE', error: error.message });
});
Run Code Online (Sandbox Code Playgroud)

请注意,React组件中引发的任何错误都可render能使React处于不一致状态,从而防止后续事件并使应用程序对UI事件无响应。React Fiber通过错误边界解决了这个问题。


Oll*_*liM 0

您可以考虑将错误处理程序移动到前一个then块中。

我写了一个简单的原理演示:https://codepen.io/anon/pen/gWzOVX?editors=0011

const fetch = () => new Promise((resolve) => {
  setTimeout(resolve, 100);
});

const fetchError = () => new Promise((resolve, reject) => {
  setTimeout(reject, 200)
});

fetch()
  .then(() => { throw new Error("error") })
  .catch(() => { console.log("error in handler caught") })

fetch()
  .then(() => { throw new Error("error") }, 
        () => { console.log("error in handler not caught") })

fetchError()
  .then(() => { throw new Error("error") })
  .catch(() => { console.log("error in fetch caught 1") })

fetchError()
  .then(() => { throw new Error("error") }, 
        () => { console.log("error in fetch caught 2") })
Run Code Online (Sandbox Code Playgroud)