当使用 redux-saga 发送一个动作时取消一个 saga

新手上路,请多包涵

当 START 动作被调度时,我为秒表 React 组件启动一个计时器:

 import 'babel-polyfill'
import { call, put } from 'redux-saga/effects'
import { delay, takeEvery, takeLatest } from 'redux-saga'
import { tick, START, TICK, STOP } from './actions'

const ONE_SECOND = 1000

export function * timerTickWorkerSaga (getState) {
  yield call(delay, ONE_SECOND)
  yield put(tick())
}

export default function * timerTickSaga () {
  yield* takeEvery([START, TICK], timerTickWorkerSaga)
  yield* takeLatest(STOP, cancel(timerTickWorkerSaga))
}
/*
  The saga should start when either a START or a TICK is dispatched
  The saga should stop running when a stop is dispatched
*/

当从我的组件发出 STOP 动作时,我无法停止 saga。我尝试使用 cancelcancelled 我的工人传奇中的效果:

 if(yield(take(STOP)) {
  yield cancel(timerTickWorkerSaga)
}

以及第一个代码块中的方法,我尝试从观看服务中停止传奇。

原文由 vamsiampolu 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 340
2 个回答

看起来这里发生了一些事情:

  1. cancel 副作用 采用 Task 对象作为其参数。您在上面的代码中传递给它的只是创建 saga/Generator 对象的 GeneratorFunction 。有关生成器及其工作原理的精彩介绍,请查看 这篇文章
  2. 您正在使用 yield*takeEverytakeLatest 生成器之前。使用 yield*传播整个序列。所以你可以这样想:它正在填充这条线

yield* takeEvery([START, TICK], timerTickWorkerSaga)

   while (true) {
       const action = yield take([START, TICK])
       yield fork(timeTickWorkerSaga, action)
   }

而且我认为这不是您想要的,因为我相信这最终会阻塞您的 timerTickSaga 的第二行。相反,您可能想要:

    yield fork(takeEvery, [START, TICK], timerTickWorkerSaga)

这分叉了 takeEvery 效果,因此它不会阻塞下一行。

  1. 您传递给 takeLatest 的第二个参数只是一个对象 - 一个 CANCEL 效果对象takeLatest 的第二个参数实际上应该是 GeneratorFunction ,当匹配 STOP 模式的动作被调度到 Redux 存储时,它将运行。所以这真的应该是一个传奇功能。 You want this to cancel the fork(takeEvery, [START, TICK], timerTickWorkerSaga) task so that future START and TICK actions will not cause the timerTickWorkerSaga to run.您可以通过让 saga 运行 CANCEL 效果和 Task 效果来实现此目的 fork(takeEvery... 效果。我们可以将 Task 对象作为 takeLatest 传奇的 附加参数。所以我们最终得到了以下内容:
    export default function * timerTickSaga () {
       const workerTask = yield fork(takeEvery, [START, TICK], timerTickWorkerSaga)
       yield fork(takeLatest, STOP, cancelWorkerSaga, workerTask)
   }

   function* cancelWorkerSaga (task) {
       yield cancel(task)
   }

如需更多参考,请查看 redux-saga 文档中的 任务取消示例。如果 cancel 查看那里的 main 传奇,您将看到 fork 效果如何产生 Task 进一步使用对象/描述符时产生的效果 --- 效果。

原文由 rayd 发布,翻译遵循 CC BY-SA 3.0 许可协议

Redux-Saga 现在有一个方法,叫做 race race 。它将运行 2 个任务,但是当一个完成时,它会自动取消另一个。

  • https://redux-saga.js.org/docs/advanced/RacingEffects.html

  • watchStartTickBackgroundSaga 一直在运行

  • 每次开始或滴答时,开始 timerTickWorkerSaga 之间的竞赛并监听下一个 STOP 操作。

  • 当其中一个任务完成时,另一个任务将被取消,这是种族行为。

  • race 中的名称“task”和“cancel”无关紧要,它们只是有助于代码的可读性


export function* watchStartTickBackgroundSaga() {
  yield takeEvery([START, TICK], function* (...args) {
    yield race({
      task: call(timerTickWorkerSaga, ...args),
      cancel: take(STOP)
    })
  })
}

原文由 Cory Danielson 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题