[英]How do I sequence actions in RxJS/redux-observable vs redux-saga?
我已经开始深入学习 RxJs,原因之一是掌握redux-observable
副作用的方法,虽然我发现 sagas 更方便和“声明性”。 我已经学习了merge/flat/concat/switchMap
操作符,但它并没有帮助我弄清楚如何在 rxjs 中对事物进行排序。
这是我所说的“排序”的一个例子,在 Timer 应用程序的实例上,可以在一段时间后安排启动,使用redux-saga
:
export function* timerSaga() {
while (true) {
yield take('START');
const { startDelay } = yield select(); // scheduled delay
const [cancelled] = yield race([
take('CANCEL_START'),
delay(startDelay)
]);
if (!cancelled) {
yield race([
call(function*() {
while (true) {
yield delay(10);
yield put({ type: 'TICK' });
}
}),
take(['STOP', 'RESET']
]);
}
}
}
我发现这个例子在逻辑上非常一致和清晰。 我不知道如何使用 redux-observable 来实现它。 请简单地给我代码的平静,这些代码可以使用rxjs
操作符重现相同的逻辑。
在传奇(生成器)和史诗(可观察对象)之间,改变您对事件如何到达代码的思考方式很重要。
生成器满足迭代器和可迭代协议,这涉及从源中提取值/事件(在本例中为 Redux 操作),并在这些事件到达之前阻止执行。
Observable 是推而不是拉。 我们描述和命名我们感兴趣的事件流,然后我们订阅它们。 没有阻塞调用,因为我们所有的代码都是由事件发生时触发的。
此代码复制了 saga 示例中的行为。
import { interval, timer } from 'rxjs';
import { withLatestFrom, mapTo, exhaustMap, takeUntil } from 'rxjs/operators';
import { ofType } from 'redux-observable';
const myEpic = (action$, state$) => {
// A stream of all the "cancel start" actions
const cancelStart$ = action$.pipe(ofType('CANCEL_START'));
// This observable will emit delayed start events that are not cancelled.
const delayedCancellableStarts$ = action$.pipe(
// When a start action occurs...
ofType('START'),
// Grab the latest start delay value from state...
withLatestFrom(state$, (_, { startDelay }) => startDelay),
exhaustMap(
// ...and emit an event after our delay, unless our cancel stream
// emits first, then do nothing until the next start event arrives.
// exhaustMap means we ignore all other start events while we handle
// this one.
(startDelay) => timer(startDelay).pipe(takeUntil(cancelStart$))
)
);
// On subscribe, emit a tick action every 10ms
const tick$ = interval(10).pipe(mapTo({ type: 'TICK' }));
// On subscribe, emit only STOP or RESET actions
const stopTick$ = action$.pipe(ofType('STOP', 'RESET'));
// When a start event arrives, start ticking until we get a message to
// stop. Ignore all start events until we stop ticking.
return delayedCancellableStarts$.pipe(
exhaustMap(() => tick$.pipe(takeUntil(stopTick$)))
);
};
重要的是,即使我们正在创建和命名这些 observable 流,它们的行为也是惰性的——在订阅之前它们都不会被“激活”,当你向redux-observable
中间件提供这个史诗功能时就会发生这种情况。
我假设take()
返回一个 observable,还没有测试代码。 它可能可以转换为 rx 时尚,如下所示。
这里的关键是repeat()
和takeUntil()
// outter condition for starting ticker
forkJoin(take('START'), select())
.pipe(
switchMap(([, startDelay]) =>
// inner looping ticker
timer(10).pipe(switchMap(_ => put({type: 'TICK'})), repeat(),
takeUntil(race(
take('CANCEL_START'),
delay(startDelay)
))
)
/////////////////////
)
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.