调度特定操作时如何取消传奇任务
How to cancel saga task when specific action is dispatched
我正在想办法解决我的问题,但我没有在网上找到足够好的解决方案。
我需要在调度操作 LoginActionType.REQUEST_SEND
时取消 checkAuth 和注销任务。
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);
}
你可以:
- "implement" 自己完成
takeLatest
的工作。
文档说
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.
所以不用写 yield takeLatest(CheckLocalAuthActionType.REQUEST_SEND, handleCheckAuthFetch);
你可以写一个函数来做同样的事情
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);
}
}
}
(takeLatest
函数 spawn
是一个传奇,而我的实现 fork
是一个传奇,但现在不用担心)
- 我们可以为
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);
}
}
}
- 然后将
userSaga
更改为
export default function* userSaga() {
yield forkHandleCheckAuthFetch();
yield forkHandleLogoutFetch();
yield takeLatest(LoginActionType.REQUEST_SEND, handleLoginFetch);
}
那么,现在:
- 您的
CheckLocalAuthActionType.REQUEST_SEND
操作触发了 handleCheckAuthFetch
,就像在我实施之前一样
- 您的
LogoutActionType.REQUEST_SEND
操作触发了 handleLogoutFetch
,就像在我实施之前一样
LoginActionType.REQUEST_SEND
操作取消每个 运行 handleCheckAuthFetch
和 handleLogoutFetch
sagas
这就是我在我的项目中所做的,将它们抽象为实用函数取决于您,我关心您是否了解它的工作原理以及如何实现它
确实帮助我了解了如何解决我的问题。我进一步研究了 Saga 文档,最终得到了这个解决方案。
export default function* userSaga() {
const checkAuthTask = yield takeLatest(CheckLocalAuthActionType.REQUEST_SEND, handleCheckAuthFetch);
const logoutTask = yield takeEvery(LogoutActionType.REQUEST_SEND, handleLogoutFetch);
yield takeLatest(LoginActionType.REQUEST_SEND, function*(userCredentialsAction: PayloadAction<LoginActionType, UserCredentials>) {
if(checkAuthTask) yield cancel(checkAuthTask);
if(logoutTask) yield cancel(logoutTask);
yield fork(handleLoginFetch, userCredentialsAction);
});
}
我正在想办法解决我的问题,但我没有在网上找到足够好的解决方案。
我需要在调度操作 LoginActionType.REQUEST_SEND
时取消 checkAuth 和注销任务。
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);
}
你可以:
- "implement" 自己完成
takeLatest
的工作。 文档说
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.
所以不用写 yield takeLatest(CheckLocalAuthActionType.REQUEST_SEND, handleCheckAuthFetch);
你可以写一个函数来做同样的事情
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);
}
}
}
(takeLatest
函数 spawn
是一个传奇,而我的实现 fork
是一个传奇,但现在不用担心)
- 我们可以为
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);
}
}
}
- 然后将
userSaga
更改为
export default function* userSaga() {
yield forkHandleCheckAuthFetch();
yield forkHandleLogoutFetch();
yield takeLatest(LoginActionType.REQUEST_SEND, handleLoginFetch);
}
那么,现在:
- 您的
CheckLocalAuthActionType.REQUEST_SEND
操作触发了handleCheckAuthFetch
,就像在我实施之前一样 - 您的
LogoutActionType.REQUEST_SEND
操作触发了handleLogoutFetch
,就像在我实施之前一样 LoginActionType.REQUEST_SEND
操作取消每个 运行handleCheckAuthFetch
和handleLogoutFetch
sagas
这就是我在我的项目中所做的,将它们抽象为实用函数取决于您,我关心您是否了解它的工作原理以及如何实现它
export default function* userSaga() {
const checkAuthTask = yield takeLatest(CheckLocalAuthActionType.REQUEST_SEND, handleCheckAuthFetch);
const logoutTask = yield takeEvery(LogoutActionType.REQUEST_SEND, handleLogoutFetch);
yield takeLatest(LoginActionType.REQUEST_SEND, function*(userCredentialsAction: PayloadAction<LoginActionType, UserCredentials>) {
if(checkAuthTask) yield cancel(checkAuthTask);
if(logoutTask) yield cancel(logoutTask);
yield fork(handleLoginFetch, userCredentialsAction);
});
}