Redux Saga обработка ошибок с несколькими вызовами API
У меня было два блага, которые я пытаюсь преобразовать в одну сагу. Когда пользователь входит в свою панель мониторинга, он делает два вызова API, один для проектов, а другой для уведомлений. Вообще-то, следовать стандартным действиям Flux, вызывая ошибки для каждого, было тривиально, но я не уверен, как лучше всего это сделать с помощью саг. Это то, с чего я должен начать:
export function* loadDashboard() {
try {
yield put({ type: types.notificationTypes.GET_NOTIFICATIONS_REQUEST });
const [projects, notifications] = yield all([
DashboardService.getProjects,
DashboardService.getNotifications
]);
yield put({
type: types.projectTypes.GET_PROJECTS_SUCCESS,
payload: projects
});
yield put({
type: types.notificationTypes.GET_NOTIFICATIONS_SUCCESS,
payload: notifications
});
} catch (error) {
//My guess is both of these will render the same error to their reducer,
//regardless of who the originator is
yield put({
type: types.projectTypes.GET_PROJECTS_FAILURE,
error: error.toString()
});
yield put({
type: types.notificationTypes.GET_NOTIFICATIONS_FAILURE,
error: error.toString()
});
}
}
2 ответа
Я в конечном итоге объединение all()
с spawn()
:
export function* loadDashboard() {
yield all([
spawn(projectActions.getProjects),
spawn(notificationActions.getNotifications),
spawn(teamActions.getTeams)
]);
}
"Отдельные вилки (с использованием spawn). Отдельные вилки живут в своем собственном контексте выполнения. Родитель не ожидает завершения работы отсоединенных вилок. Неполученные ошибки из порожденных задач не передаются родителю. И отмена родителя не отменяет автоматически отдельные вилки (вам нужно явно отменить их).
Короче говоря, отдельные ветки ведут себя так, как корневые Sagas начали напрямую, используя API middleware.run."
Я вручную проверил это, исключив заголовки аутентификации из одного GET
запрос из 3-х, и ошибка распространялась индивидуально, в то время как остальные продолжались успешно. Я побежал, чтобы проверить, что звонки УСПЕХА поступили ПОСЛЕ сбоя, просто чтобы убедиться. Тем не менее, поведение казалось функционально эквивалентным при написании того же loadDashboard()
метод с 3 fork()
вместо 3 spawn()
звонки. Потребуется написать надлежащие тесты, чтобы выяснить, какая реализация идеальна для этого сценария.
Я думаю, что лучше репаратировать логику двух запросов API.
Это улучшает удобочитаемость и удобство обслуживания:
export function* loadDashboard() {
yield all([loadProjects, loadNotifications])
}
function* loadProjects() {
try {
yield put({ type: types.GET_PROJECTS_REQUEST })
const projects = yield call(DashboardService.getProjects)
yield put({
type: types.projectTypes.GET_PROJECTS_SUCCESS,
payload: projects
})
} catch (error) {
yield put({
type: types.projectTypes.GET_PROJECTS_FAILURE,
error: error.toString()
})
}
}
function* loadNotifications() {
try {
yield put({ type: types.notificationTypes.GET_NOTIFICATIONS_REQUEST });
const notifications = yield call(DashboardService.getNotifications)
yield put({
type: types.notificationTypes.GET_NOTIFICATIONS_SUCCESS,
payload: notifications
})
} catch (error) {
yield put({
type: types.notificationTypes.GET_NOTIFICATIONS_FAILURE,
error: error.toString()
})
}
}
Этот код немного другой, хотя.
Redux-Саги all()
на самом деле "все или ничего": если одна из задач выдает ошибку, все задачи, которые все еще выполняются, отменяются.
Я не думаю, что это то, что вы хотите, поэтому в моем коде я предотвращаю это, отлавливая ошибки на запрос.
Отмена задания и распространение отмены являются основными отличиями саг от обещаний. Эти вещи часто работают по умолчанию, поэтому не торопитесь, чтобы понять их.