J'ai un réducteur pour les clients, un autre pour AppToolbar et quelques autres ...
Disons maintenant que j'ai créé une action d'extraction pour supprimer le client et que, si cela échoue, le code dans le réducteur Clients doit être rempli, mais je souhaite également afficher une erreur globale dans AppToolbar.
Mais les clients et les réducteurs AppToolbar ne partagent pas la même partie de l'état et je ne peux pas créer une nouvelle action dans le réducteur.
Alors, comment puis-je montrer une erreur globale? Merci
UPDATE 1:
J'oublie de mentionner que j'utilise este devstack
UPDATE 2: J'ai marqué la réponse d'Eric comme étant correcte, mais je dois dire que la solution que j'utilise in este ressemble plus à une combinaison de la réponse d'Eric et de Dan ... ce qui vous va le mieux dans votre code ...
Si vous souhaitez avoir le concept "d'erreurs globales", vous pouvez créer un réducteur errors
, capable d'écouter les actions addError, removeError, etc .... Ensuite, vous pouvez vous connecter à l’arbre d’état Redux à l’aide de state.errors
et les afficher le cas échéant.
Vous pouvez aborder ce problème de différentes manières, mais l’idée générale est que les erreurs/messages globaux mériteraient que leur propre réducteur vive de manière totalement distincte de <Clients />
<AppToolbar />
. Bien sûr, si l’un ou l’autre de ces composants nécessite un accès à errors
, vous pouvez lui passer errors
comme accessoire si nécessaire.
_/Mise à jour: exemple de code
Voici un exemple de ce à quoi cela pourrait ressembler si vous deviez passer les "erreurs globales" errors
dans votre <App />
de niveau supérieur et les restituer sous forme conditionnelle (si des erreurs étaient présentes). Utiliser connect
de react-redux pour connecter votre composant <App />
à certaines données.
// App.js
// Display "global errors" when they are present
function App({errors}) {
return (
<div>
{errors &&
<UserErrors errors={errors} />
}
<AppToolbar />
<Clients />
</div>
)
}
// Hook up App to be a container (react-redux)
export default connect(
state => ({
errors: state.errors,
})
)(App);
Et en ce qui concerne le créateur de l'action, il enverrait un ( redux-thunk ) échec de succès en fonction de la réponse.
export function fetchSomeResources() {
return dispatch => {
// Async action is starting...
dispatch({type: FETCH_RESOURCES});
someHttpClient.get('/resources')
// Async action succeeded...
.then(res => {
dispatch({type: FETCH_RESOURCES_SUCCESS, data: res.body});
})
// Async action failed...
.catch(err => {
// Dispatch specific "some resources failed" if needed...
dispatch({type: FETCH_RESOURCES_FAIL});
// Dispatch the generic "global errors" action
// This is what makes its way into state.errors
dispatch({type: ADD_ERROR, error: err});
});
};
}
Bien que votre réducteur puisse simplement gérer un tableau d’erreurs, ajouter/supprimer des entrées de manière appropriée.
function errors(state = [], action) {
switch (action.type) {
case ADD_ERROR:
return state.concat([action.error]);
case REMOVE_ERROR:
return state.filter((error, i) => i !== action.index);
default:
return state;
}
}
La réponse d’Erik est correcte, mais j’aimerais ajouter qu’il n’est pas nécessaire de déclencher des actions distinctes pour ajouter des erreurs. Une autre approche consiste à avoir un réducteur qui gère toute action avec un champ error
. C'est une question de choix personnel et de convention.
Par exemple, à partir de Redux real-world
exemple qui contient une gestion des erreurs:
// Updates error message to notify about the failed fetches.
function errorMessage(state = null, action) {
const { type, error } = action
if (type === ActionTypes.RESET_ERROR_MESSAGE) {
return null
} else if (error) {
return error
}
return state
}
L'approche que je suis en train de prendre pour quelques erreurs spécifiques (validation de l'entrée utilisateur) consiste à demander à mes sous-réducteurs de lever une exception, de la récupérer dans mon réducteur de racine et de la joindre à l'objet d'action. Ensuite, j'ai une saga redux-saga qui inspecte les objets d'action pour rechercher une erreur et met à jour l'arbre d'état avec les données d'erreur dans ce cas.
Alors:
function rootReducer(state, action) {
try {
// sub-reducer(s)
state = someOtherReducer(state,action);
} catch (e) {
action.error = e;
}
return state;
}
// and then in the saga, registered to take every action:
function *errorHandler(action) {
if (action.error) {
yield put(errorActionCreator(error));
}
}
Et puis, ajouter l'erreur à l'arbre d'état est décrit par Erik.
Je l'utilise avec parcimonie, mais cela m'empêche de dupliquer la logique qui appartient légitimement au réducteur (afin qu'il puisse se protéger d'un état non valide).
ce que je fais est je centralise toute la gestion des erreurs dans l'effet sur une base par effet
/**
* central error handling
*/
@Effect({dispatch: false})
httpErrors$: Observable<any> = this.actions$
.ofType(
EHitCountsActions.HitCountsError
).map(payload => payload)
.switchMap(error => {
return of(confirm(`There was an error accessing the server: ${error}`));
});
écrivez un middleware personnalisé pour gérer toutes les erreurs liées à l'API. Dans ce cas, votre code sera plus propre.
failure/ error actin type ACTION_ERROR
export default (state) => (next) => (action) => {
if(ACTION_ERROR.contains('_ERROR')){
// fire error action
store.dispatch(serviceError());
}
}