而不是使用.takeUntil()
,它聽起來像你想使用.race()
,這是相當合適的命名。無論哪條小溪首先發射,勝利!另一個是取消訂閱。
你需要重新調整一些東西來使用它,只要你想。您希望將您立即發出的第一個動作(request.onStart(meta)
)與ajax請求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
的所有論點,這對許多人來說首先遇到它是很難理解的。如果你發現非常常見的你的史詩般做了完全相同的事情並且你想要重複使用,也許抽象整個史詩將更加清晰,並創建下面的API工具,例如userRequest
,你可以獨立測試。
(未經測試,基本上是僞代碼)
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