如何在 Redux-Saga 中暂时阻止 react-router 路由更改?

How do I block temporarily block react-router route changes in Redux-Saga?

我的用户入职流程是:

  1. 用户通过 google 进行身份验证并被标记 isRegistrationDone: false
  2. 用户确认个人资料信息,点击save
  3. save 抛出 redux action REGISTRATION_COMPLETE,配置文件设置为 isRegistrationDone: true

在我的 sagas 中,我检查 isRegComplete: false 标志。如果检测到,我希望所有用户路由更改重定向到 /reg

function* fetchUserProfile(action) {
  const { uid } = authUser
  const path = getRootPath('userProfiles')
  let userProfile = // retrieve from database

  if (userProfile.isRegistrationDone === false) {
    browserHistory.push('/reg')
    yield call(watchRouteChanges)
    let confirmedUserInfo = yield take(REGISTRATION_COMPLETE)
    // ... write to database
    yield cancel(watchRouteChanges)
  }

  browserHistory.push('/dash')
}

function* watchRouteChanges() {
  fork(takeEvery, LOCATION_CHANGE, redirectToRegistration)
  return
}
function redirectToRegistration(action) {
  const destination = action.payload.pathName
  if (destination !== '/reg') browserHistory.push('/reg')
  return
}

这有效 hunky-dory 直到 yield cancel(watchRouteChanges),抛出:

utils.js:191 uncaught at sagas 
 at takeEvery 
 at fetchUserProfile 
 Error: cancel(task): argument function watchRouteChanges() {
      return _regenerator2.default.wrap(function watchRouteChanges$(_context2) {
        while (1) {
          switch (_context2.prev = _context2.next) {
            case 0:
              (0, _effects.fork)(_reduxSaga.takeEvery, _location.LOCATION_CHANGE, redirectToRegistration);
              return _context2.abrupt('return');

            case 2:
            case 'end':
              return _context2.stop();
          }
        }
      }, _marked[1], this);
    } is not a valid Task object 
(HINT: if you are getting this errors in tests, consider using createMockTask from redux-saga/utils)
    at cancel (http://192.168.0.103:3000/app.1b8181c5bf9c72be8a4e.js:27590:12)
    at fetchUserProfile$ (http://192.168.0.103:3000/app.1b8181c5bf9c72be8a4e.js:27992:39)
    at tryCatch (http://192.168.0.103:3000/app.1b8181c5bf9c72be8a4e.js:26312:41)
    at Generator.invoke [as _invoke] (http://192.168.0.103:3000/app.1b8181c5bf9c72be8a4e.js:26586:23)
    at Generator.prototype.(anonymous function) [as next] (http://192.168.0.103:3000/app.1b8181c5bf9c72be8a4e.js:26345:22)
    at next (http://192.168.0.103:3000/app.1b8181c5bf9c72be8a4e.js:28480:28)
    at Object.currCb [as cont] (http://192.168.0.103:3000/app.1b8181c5bf9c72be8a4e.js:28554:8)
    at end (http://192.168.0.103:3000/app.1b8181c5bf9c72be8a4e.js:28521:24)
    at Object.task.cont (http://192.168.0.103:3000/app.1b8181c5bf9c72be8a4e.js:28331:12)
    at next (http://192.168.0.103:3000/app.1b8181c5bf9c72be8a4e.js:28490:36)log @ utils.js:191end @ proc.js:299abort @ proc.js:95task.cont @ proc.js:108end @ proc.js:305abort @ proc.js:95task.cont @ proc.js:108end @ proc.js:305abort @ proc.js:95task.cont @ proc.js:108next @ proc.js:281currCb @ proc.js:338end @ proc.js:305task.cont @ proc.js:115next @ proc.js:274currCb @ proc.js:338checkEffectEnd @ proc.js:579chCbAtIdx @ proc.js:594currCb @ proc.js:338

重定向逻辑似乎工作正常,但我当然需要取消它才能使此过程正常进行。

有更好的方法吗?还是我的方法有误?

cancel 效果需要任务描述符作为参数,而不是 function/generator 或其他任何东西。你的情况:

...
if (userProfile.isRegistrationDone === false) {
    browserHistory.push('/reg')
    const task = yield call(watchRouteChanges) // <-- Save task descriptor
    let confirmedUserInfo = yield take(REGISTRATION_COMPLETE)
    // ... write to database
    yield cancel(task) // <-- Pass descriptor for cancellation
}
...

请查看文档:http://yelouafi.github.io/redux-saga/docs/api/index.html#canceltask