Reputation: 1161
I have two sets of actions that I would like to be able to call from different parts of my app via redux. However, I want to run them in the correct order, and make sure that set b is never run before set a.
For example, let's say I have two actions, configure
and execute
. I need to make sure that execute
is never run before configure
, but they may be dispatched out of order. In that case, I need to execute
to be enqueued and only processed once configure
has finished.
Is this possible to do in redux-saga?
I've tried the following, which doesn't seem to be blocking at all:
function* configureSaga({ payload }): IterableIterator<any> {
yield put(aFirstThing(payload));
yield put(aSecondThing());
}
function* executeSaga({ payload }): IterableIterator<any> {
yield put(aThirdThing(payload));
yield put(aFourthThing());
}
export function* adsSaga(): IterableIterator<any> {
const configureChanel = yield actionChannel({ type: 'configure' });
yield takeEvery(configureChanel, configureSaga);
yield takeEvery({ type: 'execute' }), executeSaga);
}
Given two dispatches in the following order:
dispatch({ type: 'execute' })
dispatch({ type: 'configure' })
I need the aFirstThing, aSecondThing, aThirdThing, aFourthThing
actions executed in that order.
Is such a thing possible with redux-sagas?
Upvotes: 1
Views: 1735
Reputation: 4975
takeEvery
is useful for the most common cases, but for more complex ones you will often end up writing a custom cycle instead. The implementation will differ based on how you want to deal with extra actions dispatched during configuration/execution.
Ignore all additional configure/execute actions (while waiting for the second action) + Ignore all actions until the configuration is done:
export function* adsSaga() {
while (true) {
const [executePayload, configurePayload] = yield all([
take('configure'),
take('execute'),
])
yield call(configureSaga, configurePayload);
yield fork(executeSaga, executePayload);
}
}
Ignore all additional configure/execute actions (while waiting for the second action) + Buffer all actions until the configuration is done:
export function* rootSaga() {
const configureChan = yield actionChannel('configure');
const executeChan = yield actionChannel('execute');
while (true) {
const [executePayload, configurePayload] = yield all([
take(configureChan),
take(executeChan),
])
yield call(configureSaga, configurePayload);
yield fork(executeSaga, executePayload);
}
}
To make the configure+execute actions to wait for each oher you can use the combination of all+take. You need the actionChannel only when you want to deal with multiple "rounds" of the configure+execute combo.
You can modify these solutions to e.g. buffer only the configure or execute action. Or if you want to ignore all actions until both configuration and execution is done use call
instead of fork
to run the executeSaga
. You can also allow multiple configurations run at the same time by putting the call+fork
effect inside another forked saga. There is also option to pass custom buffer to the action channel if you want to e.g. buffer max one action at a time.
Upvotes: 1