reactjs - Redux Saga - 无法取消任务

标签 reactjs generator redux-saga

我设置了一个与 redux saga 一起使用的 React 项目,但由于某种原因,我无法取消正在运行的 saga/操作任务。预期是,在执行某些操作后(例如用户离开或单击按钮),正在运行的传奇将被取消。 try catch 取消的操作,但在传奇完全运行后不会发生:

function* fetchOverviewSaga(): SagaReturnType<any> {
  try {
    yield delay(5000);
    
    console.log('still running');

    const response = yield call(getOverviewData);

    console.log('still running');

    yield all([
        put(updateTagsPendingState(false)),
        put(updateTagsDataState(response.items)),
      ]);

  } finally {
    if(yield cancelled()) {
      console.log('saga task canceled');
    }
  }
}

function* cancelOverviewSaga(): SagaReturnType<any> {
  const runningAction = yield fork(fetchOverviewSaga);

  yield cancel(runningAction);
}

function* overviewSaga() {
  yield all([
    takeLatest(startOverview, fetchOverviewSaga),
    takeLatest(cancelOverview, cancelOverviewSaga)
  ]);
}

结果是,即使在分派(dispatch)操作进行取消 (cancelOverviewSaga) 后,fetchOverviewSaga 仍然运行,只有在它完全完成运行后,do 才会在 if(yield cancelled()) 中被捕获。不确定这是否是实际行为,预计会在要求时取消。任何想法都非常受欢迎。

*编辑:

调用取消操作后,fetchOverviewSaga 似乎被取消,因为它确实记录了saga任务已取消,但是剩下运行的是来自的 block >yield all([..])),查看控制台,问题可能出在该 block 内

*编辑2:

为了更好地说明行为:

  • 调度 startOverview 操作
  • 立即取消
  • 日志:saga 任务已取消
  • 5000ms 后(延迟在 fetchOverviewSaga 中完成)
  • 日志:“仍然运行”x2 并从 fetchOverviewSaga 调度所有 yield

最佳答案

同一个传奇可以在多个实例中独立运行。所以例如如果你这样做

const task1 = yield fork(mySaga);
const task2 = yield fork(mySaga);
task1 === task2 // false

它将运行两个独立的 mySaga 实例,每个实例都有自己的任务。如果您取消其中一项,则不会取消另一项。因此,在 cancelOverviewSaga 中 fork 并立即取消 fetchOverviewSaga saga 不会对因分派(dispatch) startOverview 操作而运行的 saga 产生任何影响。

在这种情况下,您可以使用例如实现目标的race效果:

function* fetchOverviewSaga() {
  try {
    // your fetching logic ...
  } finally {
    if (yield cancelled()) {
      console.log("saga task canceled");
    }
  }
}

function* startOverviewSaga() {
  yield race([
    call(fetchOverviewSaga),
    take(cancelOverview),
  ]);
}

function* overviewSaga() {
  yield takeLatest(startOverview, startOverviewSaga);
}

如果数组中的项目完成,则竞赛效果会等待一个项目,然后取消所有其他项目,因此:

  • 如果在 fetchOverviewSaga 完成之前调度 cancelOverview 操作,它将取消 fetchOverviewSaga
  • 如果 fetchOverviewSaga 在调度取消操作之前完成,它将停止等待取消操作。

工作演示: https://codesandbox.io/s/https-stackoverflow-com-questions-69717869-redux-saga-unable-to-cancel-task-vu4b0?file=/src/index.js

关于reactjs - Redux Saga - 无法取消任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69717869/

相关文章:

javascript - 下一个js滚动事件不调用滚动?

javascript - 如何扩展生成器类?

python - 控制嵌套列表/字符串的递归(不检查类型)

javascript - redux-saga catch 加载资源失败:net::ERR_CONNECTION_REFUSED

javascript - react Hook : dispatch action from useEffect

javascript - React/redux 应用程序在 Safari 上呈现空白屏幕

javascript - CodeMirror 不适用于 React/Webpack

javascript - 为什么在这个简单的例子中 `this.refs` 会返回 undefined?

javascript - 确定 React `onFocus` 事件是否由鼠标、键盘、编程触发?

c++ - C++中的定时发生器