2016-12-08 3 views
3

私はredux-observableドキュメントからcancellation recipeで始まり、少し拡張したいと考えています。基本的にはキャンセルに応じてアクションを送信する

私は

これは私がこれまでに思い付いたものですなど、私はクリーンアップに別のアクションを派遣したいtakeUntilを使用して、キャンセルがトリガされた後のシナリオを持っている:https://jsbin.com/zemenu/195/edit?js,output

スタート」 Fetch User Info "をクリックし、Cancelを押します。私はそれがこの順序でアクションを実行したい:
- USER/FETCH
- REQUEST/STARTED
- USER/CANCELLED
- REQUEST/CANCELLED

これは私が今それを設定しているように動作します。しかし、dispatchrequestSequence関数に渡してからfinallyでトリガする必要があります。観察可能な演算子でこれを行うためのよりクリーンな方法がありますか?したがって、USER.CANCELLEDがトリガーされると、最後のアクションは、requestSequenceの内部にマッピングされます。

Redux loggerが有効になっているので、コンソールですべての操作を確認してください。

答えて

6

.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 
}); 
+0

ありがとう! 'createApiEpic'アプローチはもっとクリーンなようです。 – winkerVSbecks

+0

@winkerVSbecksようこそ。 – jayphelps

関連する問題