I am dispatching an action let's say "GET_STATUS" in a loop for X number of time from a component. In saga file I have
function* actionWatcher() {
yield all([
takeLatest(Actions.GET_LATEST, getLatest),
]);
}
Inside getLatest*
function there is this API call
//Some code
const results = yield call(api, {params});
//code after
callback()
I can clearly see API being called X number of time in network and also in chrome debugger I can see //Some code
is executed X number of time. But //code after
is executed only once in the end and callback
function is being called just once in the end.
I am expecting to be called for each occurrence.
If multiple Actions.GET_LATEST
happen in rapid succession, then takeLatest
is designed to cancel the old saga, and start a new one. If the saga is canceled while it's executing const results = yield call(api, {params});
, that means it will never get to callback()
If you don't want them to be canceled, then use takeEvery
instead of takeLatest
function* actionWatcher() {
yield all([
takeEvery(Actions.GET_LATEST, getLatest),
]);
}
If you want to keep the cancellation, but you need the callback to be called even if it's cancelled, you can use a try/finally:
function* getLatest() {
try {
const results = yield call(api, {params});
} finally {
// This code will run whether it completes successfully, or throws an error, or is cancelled
callback();
}
}
If you need to specifically check whether it was cancelled in order to perform custom logic, you can do so with an if (yield cancelled())
in the finally block:
function* getLatest() {
try {
const results = yield call(api, {params});
callback(); // This line will only run if it's not cancelled and does not throw
} finally {
if (yield cancelled()) {
// This line will only run if cancelled
}
}
}