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?
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
}
}
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.