styke
styke

Reputation: 2174

Can you call a saga and continue execution only when a different saga is finished?

Our app uses an ATTEMPT - SUCCESS - FAILURE approach to handling our responses from the server.

I have a generator function that needs to behave like this:

function * getSingleSectorAttempt(action) {
  const sectors = yield select(getSectors);
  if (!sectors) {
    //If there are no sectors, I need to call the GET_SECTORS_ATTEMPT action
    //and only restart/continue this saga when the GET_SECTORS_SUCCESS action is fired
  }
  const id = sectors[action.name].id;
  try {
    const response = yield call(api.getSector, id);
    //...
  } catch (err) {
    //...
  }
}

From what I've read of the Redux Saga documentation, this does not seem immediately possible. However, I would like to see if I'm missing something. I've already tried this:

yield fork(takeLatest, Type.GET_SECTORS_SUCCESS, getSingleSectorAttempt);
yield put(Actions.getSectorsAttempt());

in the if(!sectors) conditional block, but while this works it does not persist the initial GET_SINGLE_SECTOR_ATTEMPT action parameters, and I am not sure how to get it to do so without getting into callback and argument spaghetti.

Upvotes: 0

Views: 623

Answers (2)

VonD
VonD

Reputation: 5155

The effect allowing you to wait for an action to be dispatched is take. In your case:

function* getSingleSectorAttempt(action) {
  let sectors = yield select(getSectors);
  if (!sectors) {
    yield put(getSectorsAttempt());
    yield take(GET_SECTORS_SUCCESS);
    sectors = yield select(getSectors);
  }
  // resume here as normal
}

Your own answer could have unexpected side-effects. For example, if getSectors can return a falsy value several times in the lifetime of the app, you would have several forked processes waiting for GET_SECTORS_SUCCESS to be dispatched, and each executing your side-effect, each keeping a reference to the action that triggered it.

Upvotes: 1

styke
styke

Reputation: 2174

Oops, figured it out:

  function* getSingleSectorAttempt(action) {
    const sectors = yield select(getSectors);
    if(!sectors){
      //Pass initial action in a callback function like so:
      yield fork(takeLatest, Type.GET_SECTORS_SUCCESS, () => getSingleSectorAttempt(action));
      yield put(Actions.getSectorsAttempt());
    } else {
      const id = sectors[action.name].id;
      try {
        const response = yield call(api.getSector, id);
        //...
      } catch (err) {
        //..
      }
    }
  }

Upvotes: 0

Related Questions