4

redux-observable docs のキャンセル レシピから始めて、少し拡張したいと思います。

基本的に、キャンセルがトリガーされた後、takeUntil別のアクションをディスパッチしてクリーンアップするなどのシナリオがあります。

これは私がこれまでに思いついたものです: https://jsbin.com/zemenu/195/edit?js,output

「ユーザー情報の取得」を開始し、[キャンセル] をクリックします。次の順序でアクションを実行したい:
- USER/FETCH
- REQUEST/STARTED
- USER/CANCELLED
-REQUEST/CANCELLED

これは、現在セットアップしている方法で機能します。dispatchしかし、私は関数への受け渡しに依存しrequestSequence、それを でトリガーする必要がありfinallyます。観察可能な演算子だけでこれを行うためのよりクリーンな方法はありますか? したがって、それUSER.CANCELLEDがトリガーされると、いくつかの最終アクションがrequestSequenceオブザーバブル内にマップされます。

Redux ロガーが有効になっているため、コンソールですべてのアクションを確認してください。

4

1 に答える 1

7

を使用する代わりに、かなり適切な名前の.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
});
于 2016-12-08T06:11:53.160 に答える