使用多个API调用的Redux saga错误处理

时间:2018-11-16 01:12:11

标签: redux-saga

我有两个重击,试图将其转换为一个传奇。当用户登录其仪表板时,他们将进行两个API调用,一个用于项目,另一个用于通知。在笨拙中,遵循Flux标准动作调用每个动作的错误是微不足道的,但是我不确定用sagas进行操作的最佳方法是什么。这是我必须开始的:

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 个答案:

答案 0 :(得分:1)

我认为最好对两个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-saga的all() is actually all-or-nothing:如果其中一项任务抛出错误,则所有仍在运行的任务都将被取消。

我认为这不是您想要的,因此在我的代码中,我通过捕获每个请求的错误来防止这种情况。

Task cancellation和取消传播是sagas与promise的主要区别。这些东西通常默认情况下会起作用,因此请花一些时间来理解它们。

答案 1 :(得分:0)

我最终将all()spawn()组合在一起:

export function* loadDashboard() {
  yield all([
    spawn(projectActions.getProjects),
    spawn(notificationActions.getNotifications),
    spawn(teamActions.getTeams)
  ]);
}

From redux saga docs:

“分离叉(使用生成) 分离的派生存在于它们自己的执行上下文中。父级不等待分离的分叉终止。产生的任务未捕获的错误不会冒出给父级。并且取消父项不会自动取消分离的分叉(您需要明确地取消它们)。

简而言之,分离的分叉的行为就像root Sagas一样,直接使用middleware.run API开始。”

我通过从3个总数中的一个GET请求中排除了auth标头来进行了手动测试,并且该错误单独传播,而其他错误继续成功。我运行测试以确保在失败后成功到达了SUCCESS调用。但是,使用3个loadDashboard()而不是3个fork()调用编写相同的spawn()方法时,该行为在功能上似乎是等效的。将需要编写适当的测试来确定哪种方案是此方案的理想选择。