web-dev-qa-db-fra.com

Comment faire un gestionnaire d'erreurs global dans Redux et le redéfinir en cas de besoin?

Imaginez une situation de traitement du formulaire d'envoi pouvant renvoyer différentes erreurs: 400, 401, 500. Lorsque 400 est renvoyé, je souhaite afficher un message en haut du formulaire (outrepasse le comportement par défaut). Pour les autres codes d'erreur (non gérés), le gestionnaire d'erreurs (global) par défaut doit être appelé (ce qui indique un toast de notification). Ne voulez simplement pas dupliquer ce code pour chaque action

J'envoie des actions asynchrones à l'aide du middleware 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);

Je peux créer un réducteur qui gère tout {erreur: true} actions et affiche une notification contextuelle (probablement sans utiliser l'état redux, invoquant directement une méthode toast.show ()). Mais comment déterminer si cette erreur spéciale a été commise? déjà traité par un autre réducteur?

13
Konstantin Smolyakov

Au moment où une action atteint un réducteur, c'est un fait . Cela reflète quelque chose qui est déjà arrivé. Il n’a aucun sens de demander «L’autre réducteur at-il géré cette action?», Car les réducteurs sont supposés être passifs et, au sens général, ignorants de l’existence de chacun. Ils devraient s'efforcer d'être indépendants, dans la mesure du possible.

Il n’existe pas de «vrai» moyen d’accomplir ce que vous vouliez, mais comme vous utilisez déjà la convention qui consiste à traiter tout objet avec une propriété error comme une erreur globale, vous pouvez également introduire une autre convention du type «si l’action a un suppressGlobalErrorNotification indicateur alors le réducteur d'erreurs global ne devrait pas s'en soucier ».

// 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
  }
}
19
Dan Abramov

Même chose pour moi, je n'ai trouvé aucune solution qui puisse fonctionner. @ Dan Abramov a montré l'exemple, mais le problème est que lorsque vous avez des dizaines de formes, les choses deviennent plus compliquées. Chaque fois que vous devez gérer les mêmes choses, le code dupliqué commence à être ennuyeux. Par exemple:

form => client validation => CLIENT_VALIDATION_ERROR => reducer

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

Il peut y avoir une exception où nous devons gérer un tel comportement manuellement, mais dans la plupart des cas, ce n'est pas le cas.

0
Eugene Zharkov