如何在Redux中创建全局错误处理程序并在需要时覆盖它?

时间:2016-02-15 19:27:57

标签: javascript error-handling redux

想象一下处理表单提交的情况,它可以返回不同的错误:400,401,500。 返回400时,我想在表单顶部显示一条消息(覆盖默认行为)。 对于其他(未处理的)错误代码,应调用默认(全局)错误处理程序(显示通知toast)。只是不想为每一个动作复制此代码

我使用redux-thunk中间件调度异步操作

// Pseudo code
const action = (dispatch) => {

    const onSuccess = (result) => dispatch({type: 'OPERATION_SUCCESS', payload: result});
    const onError = (error) => dispatch({type: 'OPERATION_ERROR', error: true, payload: error});

    return promise.then(onSuccess, onError);

};
dispatch(action);

我可以创建一个reducer来处理所有 {error:true} 操作并显示一些弹出通知(可能没有使用redux状态,直接调用一些toast.show()方法) 但是如何确定这个特殊错误是否已经被其他一些减速器处理了?

2 个答案:

答案 0 :(得分:20)

当某个动作到达减速器时,它是事实。它反映了已经发生的事情。在问“其他减速器是否处理了这个动作?”是没有意义的,因为减速器应该是被动的,一般来说,不知道彼此的存在。在可能的情况下,他们应该努力保持独立。

没有一种“真正的”方法可以实现您想要的,但由于您已经使用将error属性作为全局错误处理任何对象的约定,因此您可能会引入另一个约定,例如“如果操作有一个suppressGlobalErrorNotification标志,则全局错误减少器不应该关心它。“

// utilities

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response
  } else {
    const error = new Error(response.statusText)
    error.response = response
    throw error
  }
}

function parseJSON(response) {
  return response.json()
}

export function post(url, data) {
  const options = {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)  
  }
  return fetch(url, options)
    .then(checkStatus)
    .then(parseJSON)
}

// action creators

import { post } from './utils'

export function submitForm(data) {
  return dispatch => post('/myform', data).then(
    response => dispatch({
      type: 'SUBMIT_FORM_SUCCESS',
      payload: response
    }),
    error => dispatch({
      type: 'SUBMIT_FORM_FAILURE',
      error: error,
      suppressGlobalErrorNotification: (
        error.response &&
        error.response.status === 400
      )
    })
  )
}

// reducers

export function error(state = null, action) {
  if (!action.error || action.suppressGlobalErrorNotification) {
    return state
  }
  if (action.type === 'RESET_ERROR') {
    return null
  }
  return action.error
}


export function form(state = {}, action) {
  switch (action.type) {
  case 'SUBMIT_FORM_FAILURE':
    return Object.assign({}, state, { isFormError: true })
  // ...
  default:
    return state
  }
}

答案 1 :(得分:0)

同样的事情,我没有找到任何可行的解决方案而不能处理它。 @Dan Abramov展示了这个例子,但问题在于,当你有数十种形式时,事情变得更加复杂。每次需要处理相同的事情时,重复的代码开始变得烦人。 例如:

form => client validation => CLIENT_VALIDATION_ERROR => reducer

                       FETCH_STARTED
form => form submit => SERVER_SIDE_SUCCESS  => reducers
                       SERVER_SIDE_ERROR

我们需要手动处理此类行为,但在大多数情况下不会这样做。