web-dev-qa-db-fra.com

redux-observable - envoie plusieurs actions redux en une seule épopée

Je cherche un moyen d'envoyer plusieurs actions redux dans une seule épopée de redux-observable middleware.

Supposons que j'ai suivi Epic. Chaque fois que l'événement SEARCH se produit, Epic charge les données du backend et envoie RESULTS_LOADED action.

searchEpic = (action$) => 
    action$
    .ofType('SEARCH')
    .mergeMap(
        Observable
        .fromPromise(searchPromise)
        .map((data) => {
            return {
                type: 'RESULTS_LOADED',
                results: data
            }
        })
    )

Supposons maintenant que j'ai besoin d'envoyer une action supplémentaire lorsque le searchPromise est résolu.

La façon la plus simple de le faire semble avoir une deuxième épopée qui écoutera RESULTS_LOADED et envoyer la deuxième action. Ainsi:

resultsLoadedEpic = (action$) => 
    action$
    .ofType('RESULTS_LOADED')
    .map(({results} => {
         return {
             type: 'MY_OTHER_ACTION',
             results
         } 
    })

Dans cet exemple simple, c'est assez simple. Mais lorsque les épopées grandissent, j'ai tendance à me retrouver avec beaucoup d'actions redux dont le seul but est de déclencher d'autres actions. De plus, une partie du code rxjs doit être répétée. Je trouve ça un peu moche.

Donc, ma question: existe-t-il un moyen d'envoyer plusieurs actions redux dans une seule Epic?

31
dotintegral

Il n'est pas nécessaire que vous fassiez un rapport entrée/sortie de un pour un. Vous pouvez donc émettre plusieurs actions en utilisant mergeMap (alias flatMap) si vous devez:

const loaded = (results) => ({type: 'RESULTS_LOADED', results});
const otherAction = (results) => ({type: 'MY_OTHER_ACTION', results});

searchEpic = (action$) => 
    action$
    .ofType('SEARCH')
    .mergeMap(
        Observable
        .fromPromise(searchPromise)
        // Flattens this into two events on every search
        .mergeMap((data) => Observable.of(
          loaded(data),
          otherAction(data))
        ))
    )

Notez que tout opérateur Rx qui accepte un observable peut également accepter une promesse, un tableau ou un itérable; les consommer comme s'ils étaient des flux. Nous pourrions donc utiliser un tableau à la place pour le même effet:

.mergeMap((data) => [loaded(data), otherAction(data)])

Lequel vous utilisez dépend de vos préférences de style personnel et de votre cas d'utilisation.

33
paulpdaniels

Ou peut-être que vous avez trois actions,

API_REQUEST, API_RUNNING, API_SUCCESS,

searchEpic = (action$) => 
action$
.ofType('API_REQUEST')
.mergeMap((action) => {
   return concat(
       of({type: 'API_RUNNING'}),
       Observable.fromPromise(searchPromise)
        .map((data) => {
          return {type: 'API_SUCCESS', data}; 
        }),
    );
});
1
Qiang