javascript - reconocer - ¿Cuál es la mejor manera de lidiar con un error de recuperación en react redux?
reconocer errores y pedir disculpas (6)
El enfoque que estoy tomando actualmente para algunos errores específicos (validación de entrada del usuario) es hacer que mis subreductores arrojen una excepción, la atrapen en mi reductor raíz y la adjunten al objeto de acción. Luego tengo una saga redux que inspecciona los objetos de acción en busca de un error y actualiza el árbol de estado con datos de error en ese caso.
Entonces:
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));
}
}
Y luego agregar el error al árbol de estado es como lo describe Erik.
Lo uso con bastante moderación, pero me evita tener que duplicar la lógica que pertenece legítimamente al reductor (para que pueda protegerse de un estado no válido).
Tengo un reductor para clientes, otro para AppToolbar y algunos otros ...
Ahora digamos que creé una acción de recuperación para eliminar el cliente, y si falla tengo un código en el reductor de Clientes que debería hacer algunas cosas, pero también quiero mostrar algún error global en AppToolbar.
Pero los clientes y los reductores de AppToolbar no comparten la misma parte del estado y no puedo crear una nueva acción en el reductor.
Entonces, ¿cómo se supone que muestre un error global? Gracias
ACTUALIZACIÓN 1:
Olvidé mencionar que uso este devstack
ACTUALIZACIÓN 2: Marqué la respuesta de Eric como correcta, pero tengo que decir que la solución que estoy usando en este caso es más como una combinación de la respuesta de Eric y Dan ... Solo tiene que encontrar lo que mejor se ajuste a su código. .
Puede usar el cliente axios HTTP. Ya ha implementado la función Interceptores. Puede interceptar solicitudes o respuestas antes de que se manejen para entonces o capturarlas.
https://github.com/mzabriskie/axios#interceptors
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
Si desea tener el concepto de "errores globales", puede crear un reductor de
errors
, que puede escuchar las acciones addError, removeError, etc.
Luego, puede conectarlo a su árbol de estado de Redux en
state.errors
y mostrarlos cuando sea apropiado.
Hay varias maneras de abordar esto, pero la idea general es que los errores / mensajes globales merecerían que su propio reductor viviera completamente separado de
<Clients />
/
<AppToolbar />
.
Por supuesto, si alguno de estos componentes necesita acceso a los
errors
, puede pasarlos a ellos como un accesorio cuando sea necesario.
Actualización: ejemplo de código
Aquí hay un ejemplo de cómo se vería si pasara los errores de "
errors
globales" en su nivel superior
<App />
y lo procesara condicionalmente (si hay errores presentes).
Usando
react-redux''s
connect
para conectar tu componente
<App />
a algunos datos.
// 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);
Y en lo que respecta al creador de la acción, redux-thunk fracaso de éxito ( redux-thunk ) de acuerdo con la respuesta
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});
});
};
}
Si bien su reductor podría simplemente administrar una serie de errores, agregar / eliminar entradas de manera adecuada.
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;
}
}
escriba Middleware personalizado para manejar todos los errores relacionados con la API. En este caso, su código será más limpio.
failure/ error actin type ACTION_ERROR
export default (state) => (next) => (action) => {
if(ACTION_ERROR.contains(''_ERROR'')){
// fire error action
store.dispatch(serviceError());
}
}
lo que hago es centralizar todo el manejo de errores en el efecto por efecto
/**
* 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}`));
});
La respuesta de Erik
es correcta, pero me gustaría agregar que no tiene que disparar acciones separadas para agregar errores.
Un enfoque alternativo es tener un reductor que maneje
cualquier acción con un campo de
error
.
Este es un asunto de elección personal y convención.
Por ejemplo, del
ejemplo del
real-world
Redux
que tiene manejo de errores:
// 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
}