如何等待 saga 的执行在 redux-saga 中完成?

How to wait execution of a saga to finish in redux-saga?

我有以下场景:

export function* addCircle(circleApi, { payload }) {
    try {
        const response = yield apply(
            circleApi,
            circleApi.addCircle,
            [payload]
        );

        if (response.error_type) {
           yield put(addCircleFailedAction(response.error));
        } else {
            yield put(addCircleSucceededAction(response));
        }
    } catch (err) {
        console.error(err);
    }
}

export function* addTender(tenderApi, { payload }) {
    try {
       // NOTE: I want this to finish before continuing with rest of saga below.
       yield call(addCircleAction(payload.circlePayload));

       // Rest of saga removed for brevity.
    } catch (err) {
        console.error(err);
    }
}

所以,基本上 addCircle 是在进行 API 调用,根据它的成功,我会调用适当的 redux 操作。现在,在另一个传奇中,我调用负责 addCircle 传奇的动作,我希望它在我继续传奇的其余部分之前完成执行。我尝试使用 call,但它基本上不会等待 addCircle saga 完成执行。有什么办法可以等吗?我从我的组件内部调用 addCircle 并且我不需要等待它,但是在这个特定的实例中我必须在传奇中调用它,所以我真的需要等待它完成执行,改变应用程序的状态,以便我可以在 addTender saga 的其余部分中使用更新后的状态。有什么想法吗?

根据您的代码片段,您的 addCircle saga 将在完成执行之前分派 addCircleFailedActionaddCircleSucceededAction 动作创建者。因此,我们将不得不等待您 addTender 传奇中的那些行动。

基本上,这就是您应该做的。我只是根据动作创建者的名字猜测你的动作类型。

yield call(addCircleAction(payload.circlePayload));
yield take([ADD_CIRCLE_FAILED_ACTION, ADD_CIRCLE_SUCCEEDED_ACTION]);

// Rest of the saga

不过有一种极端情况。您没有在 addCircle saga 的 catch 块中调度任何操作。也许你可以在 catch 块内发送一个名为 addCircleExceptionAction 的动作,并等待它与其他动作一起像这样:

yield take([ADD_CIRCLE_FAILED_ACTION, ADD_CIRCLE_SUCCEEDED_ACTION, ADD_CIRCLE_EXCEPTION_ACTION]);

如果您要分派多个会触发 addRender 的操作,则无法保证 take(...) 实际上会等待 yield 调用产生的操作。

export function* addCircle(circleApi, { payload }) {
  try {
      const response = yield apply(
          circleApi,
          circleApi.addCircle,
          [payload]
      );

      if (response.error_type) {
         yield put(addCircleFailedAction(response.error));
         return response;
      } else {
          yield put(addCircleSucceededAction(response));
          return response;
      }
  } catch (err) {
      console.error(err);
      return {err};
  }
}

export function* addTender(tenderApi, { payload }) {
  try {
     //because addCircle saga is returning something you can re use it
     // in other sagas.
     const result = yield call(addCircle,circleAPI?,payload.circlePayload);
     //check for result.error_type here
     // Rest of saga removed for brevity.
  } catch (err) {
      console.error(err);
  }
}

您的代码和接受的答案将导致错误,因为 call 不将操作对象作为第一个参数(它确实采用 {context,fn} 类型对象)。

分派一个动作然后收听另一个可能是也可能不是你刚分派的动作的副作用的动作是糟糕的设计。您异步分派这些操作,并且不能保证它们都需要相同的时间来完成或提供您正在等待的副作用,它们的顺序与它们开始时的顺序相同。