redux-saga何时使用fork?

55

以下两种方法有什么区别?

export function* watchLoginUser() {
  yield takeEvery(USER_LOGIN, loginUser)
}
export function* watchLogoutUser() {
  yield takeEvery(USER_LOGOUT, logoutUser)
}
export function* watchGetParties() {
  yield takeEvery(PARTIES_GET, getParties)
}
export default function* root() {
  yield [
    fork(watchLoginUser),
    fork(watchLogoutUser),
    fork(watchGetParties)
  ]
}
export default function* root() {
  yield [
    takeEvery(USER_LOGIN, loginUser),
    takeEvery(USER_LOGOUT, logoutUser),
    takeEvery(PARTIES_GET, getParties)
  ]
}

我什么时候需要使用fork,而什么时候不需要呢?

2个回答

105
一般来说,fork在saga需要启动非阻塞任务时很有用。这里的非阻塞指的是:调用者启动了任务并继续执行而不等待它完成。
有各种情况下可以使用这个功能,但其中两个主要的是:
  • 通过逻辑域对saga进行分组
  • 保留对任务的引用以便能够取消/加入它
您的顶级saga可以作为第一个用例的示例。您可能会有类似于以下内容的东西:
yield fork(authSaga);
yield fork(myDomainSpecificSaga);
// you could use here something like yield [];
// but it wouldn't make any difference here

authSaga 很可能包括以下内容:

yield takeEvery(USER_REQUESTED_LOGIN, authenticateUser);
yield takeEvery(USER_REQUESTED_LOGOUT, logoutUser);

你可以看到这个例子等同于你所建议的,使用fork调用一个产生takeEvery调用的saga。但实际上,你只需要为了代码组织目的而这样做。takeEvery本身就是一个分叉任务,因此在大多数情况下,这将是无用的冗余。
第二种用例的示例可能如下:
yield take(USER_WAS_AUTHENTICATED);
const task = yield fork(monitorUserProfileUpdates);
yield take(USER_SIGNED_OUT);
yield cancel(task);

在这个例子中,您可以看到当调用程序saga恢复并等待USER_SIGNED_OUT操作被分发时,monitorUserProfileUpdates将执行。此外,它还可以保留对它的引用以便在需要时取消它。
为了完整起见,还有另一种启动非阻塞调用的方法:spawn。fork和spawn的区别在于从子级到父级saga的错误和取消传递方式。

3
通常情况下,对于具有多个API调用分派的某些情况,fork变得更加有用,原因是您可以通过从任务中实例化取消来拒绝这些获取操作,例如:cancel(task1); 如果最终用户强制退出应用程序或其中一个任务失败,从而导致您的说明、策略和逻辑出现问题,则取消或终止当前处理任务可能是合理的。
2种方法可以取消任务
根据redux-saga文档,非阻塞效果取消。
import { take, put, call, fork, cancel } from 'redux-saga/effects'

// ...

function* loginFlow() {
  while (true) {
    const {user, password} = yield take('LOGIN_REQUEST')
    // Non-Blocking Effect which is the fork
    const task = yield fork(authorize, user, password)
    const action = yield take(['LOGOUT', 'LOGIN_ERROR'])
    if (action.type === 'LOGOUT'){
      //cancel the task
      yield cancel(task)
      yield call(Api.clearItem, 'token')
    }
  }
}

或者


import {call, put, fork, delay} from 'redux-saga/effects';
import someAction from 'action/someAction';

function* fetchAll() {
  yield fork(fetcher, 'users');
  yield fork(fetcher, 'posts');
  yield fork(fetcher, 'comments');
  yield delay(1500);
}

function* fetcher(endpoint) {
  const res = yield call(fetchAPI, endpoint);
  if (!res.status) {
    throw new Error(`Error: ${res.error}`);
  }
  yield put(someAction({payload: res.payload}));
}

function* worker() {
  try {
    yield call(fetchAll);
  } catch (err) {
    // handle fetchAll errors
  }
}

function* watcher() {
  yield takeEvery(BLOGS.PUSH, worker);
}

欢迎您:)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接