2016-06-07 38 views
7

我開始一個定時器秒錶陣營組件時,啓動操作被分派:取消傳奇時的動作與終極版 - 傳奇派出

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行動出動從我的組件。

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

以及在第一代碼塊,我試圖阻止從觀看服務撒加的辦法:我一直在使用從我的工人傳奇中cancelcancelled效果嘗試。

回答

9

貌似幾件事情是怎麼回事:

  1. cancel副作用takes a Task object as its argument。上面代碼中傳入的內容僅爲創建saga/Generator對象的GeneratorFunction。有關發電機及其工作原理的詳細介紹,請查看this article
  2. 您在takeEverytakeLatest發電機前使用yield*。使用yield*spread the whole sequence。所以,你可以認爲它像這樣的:它的填充線

    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 effect objecttakeLatest的第二個參數實際上應該是GeneratorFunction,當匹配STOP模式的操作被分派到Redux存儲區時將運行該參數。所以這應該是一個傳奇功能。您希望此操作取消fork(takeEvery, [START, TICK], timerTickWorkerSaga)任務,以便將來的STARTTICK操作不會導致timerTickWorkerSaga運行。您可以通過讓該事件與fork(takeEvery...效果產生的Task對象運行CANCEL效果來實現此目的。我們可以將Task對象作爲additional argument轉換爲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-傳奇文檔檢查出task cancellation example。如果您在那裏查看main傳奇,您會看到fork效果如何產生一個Task對象/描述符,當產生cancel效果時,該對象/描述符將進一步向下使用。

+0

正如你可能已經懷疑的可讀性,我一直忽略了ES6發電機,感謝您的答案和有用的資源。 – vamsiampolu

4

rayd的回答非常正確,但在takeEvery和TakeLatest內部做叉的方式上有點多餘。 你可以看到解釋here

因此,代碼應該是:

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

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

終極版 - 佐賀有一個方法對於現在這個樣子,這就是所謂的種族race。它將運行2個任務,但是一旦完成,它將自動取消另一個任務。

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

  • watchStartTickBackgroundSaga始終運行

  • 每當有一個開始或剔,開始timerTickWorkerSaga和聽力之間的競爭在未來停止動作。
  • 當其中一個任務完成時,另一個任務被取消 這是比賽的行爲。
  • 名稱「任務」和「取消」的比賽並不重要的內部,他們只是幫助代碼

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