2016-06-07 14 views
7

ich einen Timer für eine Stoppuhr starten Komponente reagieren, wenn eine Aktion START ausgelöst wird:eine Saga abbrechen, wenn eine Aktion mit redux-Saga versandt

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 
*/ 

ich Schwierigkeiten haben, die Saga zu stoppen, wenn die STOP Aktion ausgelöst wird von meiner Komponente. Ich habe versucht, mit cancel und cancelled Effekten aus meiner Arbeiter Saga:

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

sowie den Ansatz in dem ersten Codeblock, in dem ich versuche, und die Sage von der Beobachtung Dienst zu beenden.

Antwort

9

Sieht aus wie ein paar Dinge sind hier los:

  1. Die cancel Nebenwirkung takes a Task object as its argument. Was Sie in den obigen Code eingeben, ist nur die GeneratorFunction, die das Objekt saga/Generator erzeugt. Für ein gutes Intro zu Generatoren und wie sie funktionieren, sehen Sie sich this article an.
  2. Sie verwenden yield* vor den takeEvery und takeLatest Generatoren. Unter Verwendung von wird spread the whole sequence. So können Sie denken es so: dass es

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

    mit

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

    in der Leitung ist Füllung Und ich glaube nicht, das ist das, was Sie vorhaben, für, weil ich glaube, Dies blockiert die zweite Zeile Ihres timerTickSaga. Stattdessen möchten Sie wahrscheinlich:

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

    Diese Gabeln aus dem takeEvery Effekt, damit es nicht die nächste Zeile blockieren. Das zweite Argument, das Sie in takeLatest übergeben, ist nur ein Objekt - ein CANCEL effect object. Das zweite Argument zu takeLatest sollte eigentlich eine GeneratorFunction sein, die ausgeführt wird, wenn eine Aktion, die dem STOP-Muster entspricht, an den Redux-Speicher gesendet wird. Das sollte wirklich eine Saga-Funktion sein. Sie möchten, dass die Task fork(takeEvery, [START, TICK], timerTickWorkerSaga) abbricht, sodass zukünftige Aktionen START und TICK nicht dazu führen, dass timerTickWorkerSaga ausgeführt wird. Sie können dies erreichen, indem Sie die Saga einen CANCEL Effekt mit dem Task Objekt ausführen, das aus dem fork(takeEvery... Effekt resultierte. Wir können das Task Objekt als additional argument zu der takeLatest Saga. So landen wir mit etwas entlang der Linien von:

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

Weitere Referenz die task cancellation example in der Redux-Saga docs Check-out. Wenn Sie in der main Saga dort schauen, werden Sie sehen, wie der fork Effekt ein Task Objekt/Deskriptor liefert, der weiter unten verwendet wird, wenn der cancel Effekt erzielt wird.

+0

Wie Sie vermutet hätte, ich habe ES6 Generatoren vernachlässigt, Danke für die Antwort und die nützlichen Ressourcen. – vamsiampolu

4

Die Antwort von rayd ist sehr korrekt, aber ein bisschen überflüssig in der Art, dass takeEvery und takeLatest intern eine Gabelung machen. Sie können die Erklärung siehe here:

So sollte der Code sein:

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

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

Redux-Saga ein Verfahren hierfür hat jetzt, es race genannt Rennen. Es wird 2 Aufgaben ausführen, aber wenn einer beendet ist, wird der andere automatisch abgebrochen.

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

  • watchStartTickBackgroundSaga immer läuft

  • Jedes Mal gibt es einen Start oder kreuzen, ein Rennen zwischen timerTickWorkerSaga starten und hören für die nächste STOP-Aktion.
  • Wenn eine dieser Aufgaben beendet wird, wird die andere Aufgabe abgebrochen Dies ist das Verhalten der Rasse.
  • Die Namen „Aufgabe“ und „Abbrechen“ innerhalb der Rasse keine Rolle, sie helfen nur Lesbarkeit des Codes

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