gkeenley
gkeenley

Reputation: 7358

Redux saga: how to cancel one task from another that didn't initiate it?

I'm reading this article on cancelling tasks in Redux saga. Basically the example they have goes like this:

function* main() {
  yield call(task1);
  yield cancel(task1);
}

function* task1() {
  <...>
}

Here main can cancel task1 because it called it. In my code I'm running the functions like this:

function* task1() {
  <...>
}

function* task2() {
  yield cancel(task1);
}

function* main() {
  takeLatest(actionCreator1, task1);
  takeLatest(actionCreator2, task2);
}

Cancelling task1 in task2 doesn't work, presumably because task2 didn't invoke task1. Does anyone know how I can approach this?

Upvotes: 0

Views: 297

Answers (1)

Nicholas Tower
Nicholas Tower

Reputation: 84912

The solution is probably to have main do it's own implementation of something similar to takeLatest, but with extra logic to cancel the other task.

If you only want action2 to do the extra cancel, then it will look something like this:

function* main() {
  let firstTask;
  let secondTask;
  while (true) {
    const action = yield take([actionCreator1, actionCreator2]);
    if (firstTask) {
      // Always cancel task 1, whether we got action 1 or action 2
      yield cancel(firstTask);
    }
    if (action.type === "the type of action 1") {
      firstTask = yield fork(task1, action);
    } else {
      if (secondTask) {
        // Only cancel task 2 if we got action 2
        yield cancel(secondTask);
      }
      secondTask = yield fork(task2, action);
    }
  }
}

If you want both actions to cancel both tasks, it's a bit simpler:

function* main() {
  let task;
  while (true) {
    const action = yield take([actionCreator1, actionCreator2]);
    if (task) {
      yield cancel(task);
    }
    if (action.type === "the type of action 1") {
      task = yield fork(task1, action);
    } else {
      task = yield fork(task2, action);
    }
  }
}

Upvotes: 1

Related Questions