Problem:
There is a problem with takeLatestRequest
Version:
@ackee/antonio-utils@4.0.11
Steps to reproduce:
- dispatch a new action for a new request
- dispatch a next action with the same requestId
- both the previous handler and the handler for the next action are cancelled
A bit different yet working solution, might take an inspiration:
import type { AnyAction } from 'redux';
import type { Task } from 'redux-saga';
import { call, cancel, cancelled, fork, put, take } from 'redux-saga/effects';
export interface ActionCreator<Type extends string = string> {
(...args: any[]): {
type: Type;
};
toString: () => Type;
}
export function takeLatestRequest<R extends ActionCreator>(
{
actionCreator,
cancelActionFunction,
idSelector,
}: {
actionCreator: R;
idSelector: (action: ReturnType<R>) => string;
cancelActionFunction: (action: ReturnType<R>) => AnyAction;
},
handler: (action: ReturnType<R>, signal: AbortSignal) => void,
) {
const tasks = new Map<string, Task>();
return fork(function* () {
try {
while (true) {
const action: ReturnType<R> = yield take(actionCreator.toString());
const id = idSelector(action);
if (tasks.has(id)) {
yield cancel(tasks.get(id));
tasks.delete(id);
}
const task: Task = yield fork(function* () {
const controller = new AbortController();
try {
yield call(handler, action, controller.signal);
} finally {
if (yield cancelled()) {
controller.abort();
yield put(cancelActionFunction(action));
}
}
});
task.toPromise().then(() => {
if (tasks.has(id)) {
tasks.delete(id);
}
});
tasks.set(id, task);
}
} finally {
if (yield cancelled()) {
for (const [, task] of tasks.entries()) {
yield cancel(task);
}
}
}
});
}
Usage:
export default function* () {
yield takeLatestRequest(
{
actionCreator: updateSecret,
cancelActionFunction: action => updateSecretReset(action.meta.id),
idSelector: action => action.meta.id,
},
handler,
);
}
Problem:
There is a problem with
takeLatestRequestVersion:
@ackee/antonio-utils@4.0.11Steps to reproduce:
A bit different yet working solution, might take an inspiration:
Usage: