2016-12-08 63 views
3

我從012x開始使用可重複觀察的文檔,並希望對其進行擴展。發送取消操作

基本上我有該項取消被觸發後的場景,使用takeUntil我想派遣另一個動作進行清理等

這是我想出了迄今:https://jsbin.com/zemenu/195/edit?js,output

開始了「獲取用戶信息「,然後點擊取消。我希望它在這個順序執行操作:
- USER/FETCH
- REQUEST/STARTED
- USER/CANCELLED
- REQUEST/CANCELLED

這工作的方式我現在有它的設置。但是,我必須依靠將dispatch傳入requestSequence函數,然後在finally中觸發它。有沒有更清晰的方法來完成這一點,只需要可觀察的操作員?所以當USER.CANCELLED被觸發時,一些最終動作被映射到requestSequence可觀察值內。

Redux記錄器已啓用,因此請檢查控制檯的所有操作。

回答

6

而不是使用.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 
}); 
+0

感謝真棒解釋! 'createApiEpic'方法似乎更加清潔。 – winkerVSbecks

+0

@winkerVSbecks歡迎您! – jayphelps