I'm trying to figure out how to solve my problem, but I didn't find good enough solution on the web.
I need to cancel checkAuth and logout tasks when action LoginActionType.REQUEST_SEND
is dispatched.
function* handleLoginFetch(userCredentialsAction: PayloadAction<LoginActionType, UserCredentials>) {
try {
const response: AxiosResponse<AuthResponse> = yield call($http.put, '/users/login', userCredentialsAction.payload);
if (response.status === HttpStatusCode.OK) {
yield put(login.success(response.data.user));
}
} catch (error) {
yield put(login.failure());
}
}
function* handleCheckAuthFetch() {
try {
const response: AxiosResponse<AuthResponse> = yield call($http.get, '/users/logged-user', {
params: { 'include': 'user_user_permissions' }
});
if (response.status === HttpStatusCode.OK) {
if (yield select(getUserLoggedIn)) {
yield put(login.success(response.data.user));
} else {
yield put(checkLocalAuth.success(response.data.user));
}
}
} catch (error) {
yield put(checkLocalAuth.failure());
}
}
function* handleLogoutFetch() {
try {
const response: AxiosResponse = yield call($http.put, '/users/logout');
if (response.status === HttpStatusCode.OK) {
yield put(logout.success());
}
} catch (error) {
yield put(logout.failure())
}
}
export default function* userSaga() {
yield takeLatest(LoginActionType.REQUEST_SEND, handleLoginFetch);
yield takeLatest(CheckLocalAuthActionType.REQUEST_SEND, handleCheckAuthFetch);
yield takeEvery(LogoutActionType.REQUEST_SEND, handleLogoutFetch);
}
You could:
- "implement" by yourself what
takeLatest
does.
The docs says
Spawns a saga on each action dispatched to the Store that matches pattern. And automatically cancels any previous saga task started previously if it's still running.
So instead of writing yield takeLatest(CheckLocalAuthActionType.REQUEST_SEND, handleCheckAuthFetch);
you can write a function that does the same
export default function* forkHandleCheckAuthFetch() {
let task;
while (true) {
// this loop stops here until one of the actions is triggered
const action = yield take([CheckLocalAuthActionType.REQUEST_SEND, LoginActionType.REQUEST_SEND]);
// both the actions cancel the previous forked task (similar to what `takeLatest does`)
if (task) {
cancel(task);
}
// only the "correct" action starts the desided behaviour
if (action.type === CheckLocalAuthActionType.REQUEST_SEND) {
// a fork can be cancelled...
task = yield fork(handleCheckAuthFetch, action);
}
}
}
(the takeLatest
function spawn
s a saga while my implementation fork
s the saga but don't worry about it at the moment)
- the same we can do for the
handleLogoutFetch
export default function* forkHandleLogoutFetch() {
let task;
while (true) {
const action = yield take([LogoutActionType.REQUEST_SEND, LoginActionType.REQUEST_SEND]);
if (task) {
cancel(task);
}
if (action.type === CheckLocalAuthActionType.REQUEST_SEND) {
task = yield fork(handleLogoutFetch, action);
}
}
}
- and then change your
userSaga
to
export default function* userSaga() {
yield forkHandleCheckAuthFetch();
yield forkHandleLogoutFetch();
yield takeLatest(LoginActionType.REQUEST_SEND, handleLoginFetch);
}
So, now:
- your
CheckLocalAuthActionType.REQUEST_SEND
action triggers the handleCheckAuthFetch
as it did before my implementation
- your
LogoutActionType.REQUEST_SEND
action triggers the handleLogoutFetch
as it did before my implementation
- the
LoginActionType.REQUEST_SEND
action cancels every running handleCheckAuthFetch
and handleLogoutFetch
sagas
That's what I do in my projects, it's up to you to abstract them to a utility function, I care that you understand how it works and how to implement it