0

I have a saga loginSaga that performs the api call to get an accessToken. Once this succeeds I'd like to have bunch of other sagas to spin up that download data with this accessToken

Those sagas depend on the accessToken, so they should only run until LOGOUT_SUCCESS appears. Then they should finish. If they were currently in the process of downloading something this should be canceled, the result ignored.

This is what I have now:

function *authorize(credentials) {
  try {
    const { email, password, device_name, device_family, device_token } = credentials
    const { access_token, user } = yield call(api.loginAsync, email, password, { device_name, device_family, device_token })
    yield put(actions.loginSuccess(access_token, user))
  } catch(error) {
    console.error(error)
    if (!isCancelError(error)) {
      if (error.response && error.response.status == 401) {
        error.message = "E-Mail or Password wrong"
      }
      yield put(actions.loginError(error))
    }
  }
}

function *loginFlow() {
  while(true) {
    console.info("Waiting for account/LOGIN")
    const credentials = yield take(actions.LOGIN)
    const authorizeTask = yield fork(authorize, credentials)

    console.info("Waiting for account/LOGOUT")
    const { type } = yield take([actions.LOGOUT, actions.LOGIN_ERROR])
    cancel(authorizeTask)
    if (type == actions.LOGOUT) {
      yield call(api.logoutAsync)
      yield put(actions.logoutSuccess())
    }
  }
}

Then the on LOGIN_SUCESS depending sagas:

function *refreshUser() {
  while (true) {
    const result = yield take([actions.LOGIN_SUCCESS, actions.REFRESH_USER])
    try {
      const user = yield call(api.getUserAsync)
      yield put(actions.userRefreshed(user))
    } catch (error) {
    }
  }
}


function *getActivities(access_token) {
  console.info("fetch activities")
  try {
    const activities = yield call(api.getActivitiesAsync, access_token)
    console.info("activities fetched")
    yield put(activitiesUpdated(activities))
  } catch (error) {
  }
}

function *updateActivities() {
  while (true) {
    const { access_token } = yield take(actions.LOGIN_SUCCESS)
    console.info("Calling getActivities")
    yield call(getActivities, access_token)
    while (true) {
      const {type } = yield take([actions.REFRESH_ACTIVITIES, actions.LOGOUT])
      if (type == actions.LOGOUT) {
        break
      }
      yield call(getActivities, access_token)
    }
  }
}

And since they all need the accessToken they all have to wait until the LOGIN_FINISHED because this carries it in the payload.

Also my sagas are all started at the beginning and wait.

I thought maybe, when the authorize flow finishs it could then spin up the loginDependingSagas with the accessToken as a param.

like so:

function forkLoginDependingSagas(accessToken) { fork refreshUser(accessToken) fork updateActivities(accessToken) }

Is that a good pattern?

4

1 回答 1

0

我使用一个单独的 saga 解决了这个问题,该 saga 等待access_token根据 this 携带然后 fork sagas的动作access_token

function* authorizedFlow() {
  let payload
  while (({ payload } = yield take([actions.LOGIN_SUCCESS, actions.START_SIGNUP_SUCCESS]))) {
    const { access_token } = payload
    yield fork(logoutFlow, access_token)
    yield race({
      watchers: [
        call(refreshUser, access_token),
        call(refreshInvoices, access_token),
        call(refreshPendingTransactions, access_token),
      ],
      logout: take(actions.LOGOUT_SUCCESS),
    })
  }
}

function* logoutFlow(access_token) {
  while (yield take(actions.LOGOUT)) {
    try {
      yield call(api.logoutAsync, access_token)
      yield put(actions.logoutSuccess())
    } catch (error) {
      yield put(actions.logoutError(error))
    }
  }
}

logoutFlow 将确保依赖的 sagasrace之间的关联会access_token导致在注销成功时取消它们。

于 2016-08-29T23:24:48.913 回答