Reputation: 798
I have this type of composition of my sagas - a race between:
export function* doPollingSaga() {
try {
while (true) {
const res = yield call(fetchData, {})
if(res) {
yield put(saveResultsActionCreator(res))
if(weHaveEverythingWeWanted) {
break;
}
}
yield delay(POLLING_DELAY);
}
} catch (e) {
yield put(doSomeErrorReportingAndFinishActionCreator());
} finally {
if (yield cancelled()) {
yield put(doSomePostCancelActionCreator());
}
}
}
export default function*() {
yield race([
take(ActionTypes.CANCEL),
all([
takeLatest(ActionTypes.DO_POLLING, doPollingSaga),
// some more other sagas here
]),
]);
}
but when I dispatch ActionTypes.CANCEL
from one of the UI components - nothing happens
In redux devtools I see that it's being dispatched correctly, but polling doesn't stop, doPollingSaga
continues like nothing happened.
Inside doPollingSaga
yield cancelled() === false
all the time.
I've also tried replacing while(true)
with while(!(yield cancelled()))
but no effect as well.
From the docs I assume that everything inside all([...])
should be cancelled when ActionType.CANCEL
wins the race
Not sure if I'm missing something important about cancellation of sagas.
Upvotes: 1
Views: 222
Reputation: 108
Looks like the cause is in nesting order of race
and takeLatest
. The latter forks given saga, making it cancel-proof. You have to either listen to cancel actions inside the polling loop, or make a race
inside the takeLatest
:
function* cancellableSaga() {
yield race([take('cancel_polling'), call(doPollingSaga)]);
}
Upvotes: 3