簡體   English   中英

在可以通過redux-observable完成一些異步操作之后,如何對redux操作進行排序?

[英]How can I sequence redux actions after some async action completed in redux-observable?

語境

我有很多形式的動作: LOAD_XYZLOAD_XYZ_FAILLOAD_XYZ_SUCCESS用於需要加載的不同頁面元素。

我經常希望在加載某些項目后執行重定向( react-router ),但是由於redux-observable不會返回諾言,所以我無法在組件中執行重定向-而是必須使用reduxpush('...')來自react-router-redux

不幸的是,這導致大量重復,因為我有相同動作的LOAD_XYZLOAD_XYZ_REDIRECT_TO版本, LOAD_XYZ_REDIRECT_TO版本都有兩個史詩。

這開始感到浪費,並且冗余過多

const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .mergeMap(action =>
      ajax.getJSON(`https://api.github.com/users/${action.payload}`)
      .map(response => fetchUserFulfilled(response))
    );

const fetchUserAndRedirectEpic = action$ =>
  action$.ofType(FETCH_USER_AND_REDIRECT)
    .mergeMap(action =>
      ajax.getJSON(`https://api.github.com/users/${action.payload}`)
      .concatMap(response => [fetchUserFulfilled(response), push(action.redirectTo)])
    );

問題

是否有某種模式/方法,可以在某種異步請求完成后對要分派的動作進行排序,以避免冗余並必須實現同一史詩的多個版本。

例如,我希望有一個單獨的REDIRECT_TO操作,可以在加載項目后對其進行排序。

類似於以下(虛構)解決方案:

dispatch(fetchUser(...)).then(redirectTo("..."))
dispatchSequence(fetchUser(...), redirectTo("..."))

我知道redux-thunk可以做到這一點,但后來我錯過了所有rxjs運算符。

我可能正涉足危險地帶,但我確實找到了解決方法。

首先,我們制作一個中間件,該中間件將可觀察到的完成作為元數據添加到動作中。

import { Subject } from "rxjs";

export const AddListenerMiddleware = store => next => action => {
  const forkedAction = Object.assign({}, action, { meta: { listener: new Subject()}});
  next(forkedAction);
  return forkedAction.meta.listener.asObservable();
};

由於這是一個Subject我們可以在其上調用next發出一些值。 創建notify助手可以使我們將操作完成的時間通知所有訂閱者(以及傳遞數據)。

// notify doesn't consume but just emits on the completion observable
const notify = (action, fn) => source => 
  Observable.create(subscriber => 
    source.subscribe(emmission => {
      if (action.meta && action.meta.listener) {
        action.meta.listener.next(fn(emmission));
      }
      subscriber.next(emmission);
    })
  );

const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .mergeMap(action =>
      ajax.getJSON(`https://api.github.com/users/${action.payload}`)
      .map(response => fetchUserFulfilled(response))
      .pipe(notify(action, response => response.data))
    );

現在,我們的調度返回一個可觀察的對象,我們可以在該對象上執行標准的rxjs操作。 因此,這最終成為可能:

dispatch(fetchUser(...))
    .subscribe(({id}) => dispatch(redirectTo("/" + id)))

免責聲明:使用風險自負!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM