.takeUntil()
の代わりに、.race()
を使用したいと思うのですが、それはかなり適切です。どちらのストリームが最初に出ても、勝ちます!もう1つは登録解除されています。
必要に応じて使い方を変える必要があります。すぐに出てくる最初のアクションを分離したい場合は、request.onStart(meta)
をajaxリクエストObservable.fromPromise(apiCall(...args))
から分離してください。その後、そのAjaxとキャンセルの間で直接競争したいので、このすべてをヘルパーに入れているので、action$
のActionObservableを渡す必要があります。
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$
)
);
サイドノート:ヘルパーのこれらの種類を作るような時期尚早の抽象化に注意してください。あなたはいくつかの叙事詩で物事を繰り返すかもしれませんが、私は抽象化することで、後でgrokするのがはるかに難しくなることがわかりました。特にコードを書かずに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
});
ありがとう! 'createApiEpic'アプローチはもっとクリーンなようです。 – winkerVSbecks
@winkerVSbecksようこそ。 – jayphelps