web-dev-qa-db-fra.com

Comment attendre l'exécution d'une saga pour finir dans redux-saga?

J'ai le scénario suivant:

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

Donc, fondamentalement, addCircle effectue un appel d'API et, en fonction de son succès, j'appelle l'action de redux appropriée. Maintenant, dans une autre saga, j'appelle l'action responsable de la saga addCircle, et je veux qu'elle termine son exécution avant de continuer avec le reste de la saga. J'ai essayé d'utiliser call, mais cela n'attend pas que la saga addCircle termine son exécution. Existe-t-il un moyen de l'attendre? J'appelle addCircle depuis l'intérieur de mes composants et je n'ai pas eu besoin de l'attendre, mais dans ce cas précis, je dois l'appeler à l'intérieur de la saga, donc j'ai vraiment besoin d'attendre la fin de l'exécution, changer l'état de l'application, afin que je puisse utiliser l'état mis à jour dans le reste de la saga addTender. Des idées?

6
user9128740

Selon votre extrait de code, votre saga addCircle enverra les créateurs d'actions addCircleFailedAction ou addCircleSucceededAction juste avant la fin de l'exécution. Nous devrons donc attendre ces actions dans votre saga addTender.

Fondamentalement, c'est ce que vous devez faire. Je devine simplement vos types d'actions en fonction des noms des créateurs d'actions.

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

// Rest of the saga

Il y a cependant un cas Edge. Vous n'envoyez aucune action dans le bloc catch de votre saga addCircle. Vous pouvez peut-être envoyer une action appelée addCircleExceptionAction à l'intérieur du bloc catch et l'attendre avec les autres actions comme celle-ci:

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

Si vous distribuez plusieurs actions qui déclencheraient addRender, rien ne garantit que take (...) attendrait réellement l'action qui a résulté de l'appel de rendement.

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

Votre code et la réponse acceptée entraîneraient une erreur car appel ne prend pas un objet action comme premier argument (il prend un objet de type {context, fn}).

L'envoi d'une action puis l'écoute d'une autre action qui peut ou non avoir été un effet secondaire de l'action que vous venez d'envoyer est une mauvaise conception. Vous envoyez ces actions de manière asynchrone et rien ne garantit qu'elles prennent toutes le même temps pour se terminer ou produire l'effet secondaire que vous attendez dans le même ordre qu'elles ont été démarrées.

0
HMR