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)
  ]);
}

Из Redx Saga Docs:

"Отдельные вилки (с использованием 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() на самом деле "все или ничего": если одна из задач выдает ошибку, все задачи, которые все еще выполняются, отменяются.

Я не думаю, что это то, что вы хотите, поэтому в моем коде я предотвращаю это, отлавливая ошибки на запрос.

Отмена задания и распространение отмены являются основными отличиями саг от обещаний. Эти вещи часто работают по умолчанию, поэтому не торопитесь, чтобы понять их.

Другие вопросы по тегам