我在调度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
操作时,我无法停止传奇。我尝试在我的工作者传奇中使用cancel
和cancelled
效果:
if(yield(take(STOP)) {
yield cancel(timerTickWorkerSaga)
}
以及第一个代码块中的方法,我尝试从观看服务中停止传奇。
答案 0 :(得分:11)
看起来这里发生了一些事情:
cancel
副作用takes a Task
object as its argument。您在上面的代码中传递给它的只是创建saga / Generator对象的GeneratorFunction
。有关生成器及其工作原理的详细介绍,请查看this article。您在yield*
和takeEvery
生成器之前使用takeLatest
。使用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
效果,因此它不会阻止下一行。
您传递给takeLatest
的第二个参数只是一个对象 - CANCEL effect object。 takeLatest
的第二个参数实际上应该是GeneratorFunction
,当匹配STOP
模式的操作被调度到Redux存储时,它将运行。所以这应该是一个传奇功能。您希望此操作取消fork(takeEvery, [START, TICK], timerTickWorkerSaga)
任务,以便将来的START
和TICK
操作不会导致timerTickWorkerSaga
运行。您可以通过让saga与CANCEL
效果产生的Task
对象产生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)
}
。因此,我们最终会得到以下内容:
main
有关其他参考,请查看redux-saga文档中的additional argument。如果你查看那里的fork
传奇,你会看到Task
效果如何产生一个cancel
对象/描述符,当你产生my $delimiter = "\t";
my $line = "zyz pqr abc xyz";
my $count = () = $line =~ /$delimiter/g; # $count is now 3
print $count;
时会被进一步使用效果。
答案 1 :(得分:5)
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);
}
答案 2 :(得分:4)
Redux-Saga现在有一种方法,它被称为种族race
。它将运行2个任务,但当一个任务完成时,它将自动取消另一个任务。
watchStartTickBackgroundSaga一直在运行
export function* watchStartTickBackgroundSaga() {
yield takeEvery([START, TICK], function* (...args) {
yield race({
task: call(timerTickWorkerSaga, ...args),
cancel: take(STOP)
})
})
}