を使用する代わりに、かなり適切な名前の.takeUntil()
を使用したいようです。.race()
どちらのストリームが最初に放出されても、勝ちます! もう1つは未登録です。
必要に応じて使用するには、いくつかのものを少し再構築する必要があります。request.onStart(meta)
ajax request とは別に、すぐに発行する最初のアクションを分離したいと考えていますObservable.fromPromise(apiCall(...args))
。次に、その ajax とキャンセルの間で直接競合したいので、action$
これらすべてがヘルパーにあるため、ActionsObservable を渡す必要があります。
https://jsbin.com/suvaka/edit?js,output
function requestSequence(apiCall, args, meta, action$) {
return Observable.of(request.onStart(meta))
.concat(
Observable.fromPromise(apiCall(...args))
.map((payload) => request.onSuccess(payload, meta))
.catch((e) => Observable.of(request.onError(e, meta)))
.race(
action$.ofType(USER.CANCELLED)
.map(() => request.onCancel(meta))
)
);
}
const fetchUserEpic = (action$, store) =>
action$.ofType(USER.FETCH)
.mergeMap(action =>
requestSequence(
userRequest,
[`/api/users/${action.payload}`],
{ activity: USER.FETCH, path: 'user' },
action$
)
);
補足: この種のヘルパーを作成するなど、時期尚早の抽象化には注意してください。いくつかの叙事詩で物事を繰り返すかもしれませんが、抽象化すると、後で理解するのがはるかに難しくなる可能性があることがわかりました。特に、コードを書いておらず、Rx の専門家ではない人である場合はなおさらです。もちろん、このアドバイスがあなたとあなたのコードベースに当てはまるかどうかは、あなただけが知ることができます。
私にとって一番の混乱点は、 に渡さなければならないすべての引数ですrequestSequence
。これは、多くの人が最初に遭遇したときに理解するのが難しいでしょう。非常に頻繁にエピックがまったく同じことを行い、再利用したい場合は、エピック全体を抽象化する方がより明確になり、userRequest
独立してテストできる以下のような API ユーティリティを作成できます。
(未テスト、基本的に疑似コード)
const createApiEpic = options =>
action$ =>
action$.ofType(options.on)
.mergeMap(action =>
Observable.of(request.onStart(meta))
.concat(
options.effect(action.payload)
.map(payload => request.onSuccess(payload, meta))
.catch(e => Observable.of(request.onError(e, meta)))
.race(
action$.ofType(options.cancel)
.map(() => request.onCancel(meta))
)
)
);
const userRequest = id =>
Observable.ajax.getJSON(`/api/users/${id}`);
const fetchUserEpic = createApiEpic({
on: USER.FETCH,
effect: userRequest
cancel: USER.CANCELLED
});