调度特定动作时如何取消传奇任务

时间:2019-03-20 08:56:26

标签: redux-saga

我正在尝试找出解决问题的方法,但是我在网络上找不到足够好的解决方案。

派遣动作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);
}

2 个答案:

答案 0 :(得分:0)

您可以:

  • takeLatest自己执行的“实现”。 文档说
  

在分配给与模式匹配的商店的每个动作上产生传奇。并自动取消以前启动的任何先前的传奇任务(如果它仍在运行)。

因此,无需编写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操作会取消每次运行的handleCheckAuthFetchhandleLogoutFetch sagas

这就是我在项目中所做的事情,取决于您将它们抽象为实用程序函数,我关心您了解它的工作原理和实现方式

答案 1 :(得分:0)

NoriSte's answer确实帮助我了解了如何解决我的问题。我研究了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);
    });
}