簡體   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