ストップウォッチのタイマーを開始React STARTアクションがディスパッチされたときにコンポーネント:
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
アクションがコンポーネントからディスパッチされると、サガを停止できません。私はワーカーサガ内からcancel
およびcancelled
エフェクトを使用してみました:
if(yield(take(STOP)) {
yield cancel(timerTickWorkerSaga)
}
最初のコードブロックでのアプローチと同様に、サーガをウォッチングサービスから停止しようとします。
ここでいくつかのことが起こっているようです:
cancel
副作用 Task
オブジェクトを引数として受け取ります 。上記のコードで渡されているのは、saga/Generatorオブジェクトを作成するGeneratorFunction
だけです。ジェネレーターの概要とその仕組みについては、 この記事 をご覧ください。takeEvery
およびtakeLatest
ジェネレーターの前に_yield*
_を使用しています。 _yield*
_を使用すると、 シーケンス全体を拡散 します。だからあなたはそれをこのように考えることができます:それは行を埋めているということです
yield* takeEvery([START, TICK], timerTickWorkerSaga)
と
_while (true) {
const action = yield take([START, TICK])
yield fork(timeTickWorkerSaga, action)
}
_
そして、私はこれがあなたのtimerTickSaga
の2行目をブロックすることになると思うので、これがあなたがしようとしていることだとは思いません。代わりに、おそらく次のようにします。
_yield fork(takeEvery, [START, TICK], timerTickWorkerSaga)
_
これはtakeEvery
効果を分岐して、次の行をブロックしないようにします。
takeLatest
に渡す2番目の引数は単なるオブジェクトです CANCELエフェクトオブジェクト 。 takeLatest
の2番目の引数は、実際にはGeneratorFunction
である必要があります。これは、STOP
パターンに一致するアクションがReduxストアにディスパッチされたときに実行されます。ですから、それは本当にサガ関数であるべきです。これにより、fork(takeEvery, [START, TICK], timerTickWorkerSaga)
タスクをキャンセルして、将来のSTART
およびTICK
アクションによってtimerTickWorkerSaga
が実行されないようにすることができます。これは、_fork(takeEvery...
_エフェクトの結果であるCANCEL
オブジェクトを使用してTask
エフェクトをサガに実行させることで実現できます。 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
生成時にさらに使用されることがわかります。 ] _効果。
Redux-Sagaにはこのためのメソッドがあり、race race
と呼ばれています。 2つのタスクを実行しますが、一方が完了すると、もう一方は自動的にキャンセルされます。
watchStartTickBackgroundSagaは常に実行されています
export function* watchStartTickBackgroundSaga() {
yield takeEvery([START, TICK], function* (...args) {
yield race({
task: call(timerTickWorkerSaga, ...args),
cancel: take(STOP)
})
})
}
Raydからの答えは非常に正しいですが、takeEveryとtakeLatestが内部でforkを実行している点で少し余分です。あなたは説明を見ることができます ここ :
したがって、コードは次のようになります。
export default function* timerTickSaga() {
const workerTask = yield takeEvery([START, TICK], timerTickWorkerSaga);
yield takeLatest(STOP, cancelWorkerSaga, workerTask);
}
function* cancelWorkerSaga(task) {
yield cancel(task);
}