I have a redux-saga that I only want to fire for certain action.meta
values:
function* handleUpdateSomeStuff(action): Generator {
if (action.meta === "Special_Meta") {
// run some code
}
}
function* myConditionalSaga(): Generator {
yield takeEvery(
[ActionTypes.UPDATE_SOME_STUFF],
handleUpdateSomeStuff
);
}
function* itemSaga(): Generator {
yield all([
fork(myConditionalSaga),
// ... more sagas
]);
}
Currently, I check within handleUpdateSomeStuff
whether or not action.meta
meets a certain condition. But I feel like the code should never even get that far. However, I don't see how the action
argument might be available in myConditionalSaga
to check it there. I am thinking something like this:
function* myConditionalSaga(action): Generator {
if (action.meta === "Special_Meta") {
yield takeEvery(
[ActionTypes.UPDATE_SOME_STUFF],
handleUpdateSomeStuff
);
}
}
The above block is more meta code than anything else, as trying to pass an argument to myConditionalSaga
gives a TS error Argument of type '(action: any) => Generator<unknown, any, unknown>' is not assignable to parameter of type '{ context: unknown; fn: (this: unknown, ...args: any[]) => any; }'.
inside the fork
statement.
Is there a way to prevent handleUpdateSomeStuff
from being called based on the action.meta
of the action? I did indeed read Redux-saga takeLatest conditionally, as well as the docs on takeEvery, but I am struggling to undertsand how that may be applied to my scenario to get the desired result.
Opinions welcome in comments: Should I not even worry about it? Just let the function call reach myConditionalSaga
and handle the if
there?
take
and its variants support a function as its first argument instead of an action type (or array of action types).
So you should be able to do something like this:
function* handleUpdateSomeStuff(action): Generator {
// this runs only for when meta is "Special_Meta"
}
function* myConditionalSaga(): Generator {
yield takeEvery(action => {
return (
action.type === ActionTypes.UPDATE_SOME_STUFF &&
action.meta === "Special_Meta"
);
}, handleUpdateSomeStuff);
}
It might seem bit "wordy" like this, but if you need to limit the handlers based on the meta param more often, you can of course create some utility helper, e.g.:
const typeAndMeta = (type, meta) => action => action.type === type && action.meta === meta
yield takeEvery(typeAndMeta(ActionTypes.UPDATE_SOME_STUFF, 'Special_Meta'), saga);
or even
const takeEveryByMeta = (type, meta, saga, ...args) => {
return takeEvery(action => action.type === type && action.meta === meta, saga, ...args);
}
yield takeEveryByMeta(ActionTypes.UPDATE_SOME_STUFF, 'Special_Meta', saga);
You can easily extend these helpers to support array of types/meta values as well.