繁体   English   中英

使用redux-saga调度操作时取消传奇

[英]Cancel a saga when an action is dispatched with redux-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动作时,我无法停止传奇。 我试过在我的工作者传奇中使用cancelcancelled效果:

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

以及第一个代码块中的方法,我试图阻止来自观看服务的传奇。

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

  1. cancel副作用Task对象作为其参数 您在上面的代码中传递的内容只是GeneratorFunction saga / Generator对象的GeneratorFunction。 有关生成器及其工作原理的详细介绍,请查看本文
  2. 你在takeEvery之前使用yield*并使用takeLatest生成器。 使用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效果,因此不会阻止下一行。

  3. 你传递给takeLatest的第二个参数只是一个对象 - 一个CANCEL效果对象 takeLatest的第二个参数实际上应该是一个GeneratorFunction ,它将在匹配STOP模式的动作被调度到Redux存储时运行。 所以这应该是一个传奇功能。 您希望这取消fork(takeEvery, [START, TICK], timerTickWorkerSaga)任务,以便将来的STARTTICK操作不会导致timerTickWorkerSaga运行。 你可以通过使用由fork(takeEvery...产生的Task对象运行一个CANCEL效果来实现这一点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文档中的任务取消示例 如果你查看那里的main传奇,你会看到fork效果如何产生一个Task对象/描述符,在产生cancel效果时会进一步使用它。

rayd的答案是非常正确的,但在takeEvery和takeLatest内部正在做分叉的方式有点多余。 你可以在这里看到解释:

所以代码应该是:

export default function* timerTickSaga() {
    const workerTask = yield takeEvery([START, TICK], timerTickWorkerSaga);
    yield takeLatest(STOP, cancelWorkerSaga, workerTask);
}

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

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

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

  • watchStartTickBackgroundSaga一直在运行

  • 每次有开始或勾选时,在timerTickWorkerSaga和听取下一个STOP动作之间开始比赛。
  • 当其中一个任务完成时,另一个任务被取消,这就是种族的行为。
  • 种族内部的名称“任务”和“取消”并不重要,它们只是帮助代码的可读性

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM