传奇总是被取消

Saga always cancelled

我使用 redux-saga 并有以下代码:

function* loginFlow(username, password) {
  try {
    yield call(loginApi, username, password);
    yield put({ type: LOGIN_SUCCESS });
    yield put({ type: TOGGLE_LOGGED_DONE, payload: true });
    yield put(push('/dashboard'));
  } catch (error) {
    yield put({ type: LOGIN_ERROR, error });
  } finally {
    if (yield cancelled()) {
      console.log('ALWAYS CANCELLED');
      // yield put(replace('/login'));
    }
  }
}

// Watcher saga.
function* loginWatcher() {
  while (true) {
    const { username, password } = yield take(LOGIN_REQUESTING);
    const task = yield fork(loginFlow, username, password);
    const action = yield take([LOGOUT, LOGIN_ERROR]);
    if (action.type === LOGOUT) yield cancel(task);
    yield call(logoutUser);
  }
}

问题是 loginFlow 函数最后总是被取消(我在控制台中看到 'ALWAYS CANCELLED')。即使我从 loginWatcher.

中删除 const action = yield take([LOGOUT, LOGIN_ERROR]);yield call(logoutUser);

我看不到 LOGOUTLOGIN_ERROR 被解雇了:

知道我的代码有什么问题吗?

请注意,我在 index.js 中使用 withRouter 作为上面的 saga 所在的登录页面(否则我在重定向时会出现空白屏幕):

const withSaga = injectSaga({ key: 'login', saga }); 

export default compose( withReducer, withSaga, withConnect, )(LoginPage); 

此致

编辑: 如果在 try/catch 中包装 loginWatcher 我也会去 finally 那里:

function* loginWatcher() {
  while (true) {
    try {
      const { username, password } = yield take(LOGIN_REQUESTING);
      const task = yield fork(loginFlow, username, password);
      const action = yield take([LOGOUT, LOGIN_ERROR]);
      if (action.type === LOGOUT) yield cancel(task);
      yield call(logoutUser);
    } catch (error) {
      yield put({ type: LOGIN_ERROR, error });
    } finally {
      if (yield cancelled()) {
        console.log('HERE AS WELL');
        // yield put(push('/login'));
      }
    }
  }
}

我发布了我们收集的答案,以便这个问题对未来的读者有用。

在 redux-saga 中,通过 call()fork() 启动的传奇被递归取消。 Saga表示递归可取消任务。所以当一个 saga 被取消时,你应该检查它的父 saga,等等。

您发布的这段代码:

const withSaga = injectSaga({ key: 'login', saga });
export default compose( withReducer, withSaga, withConnect, )(LoginPage)

Google建议使用this redux-saga + react-boilerplate example。它涵盖取消以及如何禁用它。查看 link 了解相关信息。

我不熟悉 react-boilerplate(React 生态系统很大),但我想我的回答至少缩小了搜索范围。如果您感到困惑,请考虑使用 提出一个单独的问题。