2017-01-05 1 views
1

Un collègue et moi avons ajouté un flux de type "redux-observable" à notre application android et n'arrivons pas à comprendre comment créer une épopée qui cesse de recevoir des actions jusqu'à la fin du premier appel.Epic qui ignore l'action jusqu'à la fin de la première requête

A l'origine, je pensais que nous pouvions utiliser skipUntil() mais nous nous sommes rendu compte que le résultat de skipUntil() était avalé et ne passait jamais au reste de la chaîne. Ci-dessous, un code JS approximatif montrant ce que nous espérons accomplir.

const fetchUserEpic = action$ => 
    action$.ofType(FETCH_USER) 
    .skipUntil(/* first request completes */) 
    .mergeMap(action => 
     ajax.getJSON(`/api/users/${action.payload}`) 
     .map(response => fetchUserFulfilled(response)) 
     .takeUntil(action$.ofType(FETCH_USER_CANCELLED)) 
    ); 

Il est presque comme je l'ai besoin d'un opérateur skipMap() qui agit comme switchMap() mais les honneurs qu'une seule demande à la fois, tout en ignorant tous les éléments si une observable est en cours.

Merci pour vos suggestions.

Répondre

2

En supposant que vous êtes assez sûr que ce que vous avez besoin (il est généralement pas laisser tomber l'entrée pendant que vous exécutez une requête précédente signifie que le résultat est obsolète, switchMap et/ou debounce sont généralement préférés), take(1) + repeat devrait fonctionner, comme l'action observable est chaude.

const fetchUserEpic = action$ => 
    action$.ofType(FETCH_USER) 
    .take(1) 
    .concatMap(action => 
     ajax.getJSON(`/api/users/${action.payload}`) 
     .map(response => fetchUserFulfilled(response)) 
     .takeUntil(action$.ofType(FETCH_USER_CANCELLED)) 
    ) 
    .repeat() 

Voici un extrait simulant la logique.

// simulate action$.ofType(FETCH_USER) every second 
 
const obs1 = Rx.Observable.interval(1000).publish() 
 
obs1.connect() 
 

 
function getStuff(i) { 
 
    return Rx.Observable.timer(i*1000).mapTo(i) 
 
} 
 

 
obs1.take(1).concatMap(getStuff).repeat().subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.2/Rx.js"></script>

+0

Merci. Je vais essayer. Le cas d'utilisation auquel nous pensons est celui où l'utilisateur clique rapidement sur un bouton de soumission ou tente d'actualiser les données avant que la réponse d'origine ait une chance de revenir. – jachenry

+1

Peut-être désactiver le bouton Soumettre alors que la requête est en vol est une option meilleure/plus sûre (basé sur l'état, défini dans FETCH_USER, réinitialisé dans FETCH_FULLFILLED/ANNULÉ) – Gluck

1

Vous n'avez pas besoin de faire quoi que ce soit de fantaisie, il y a déjà un opérateur pour cela appelé exhaustMap. exhaustMap est similaire à concatMap sauf qu'il supprime silencieusement les demandes qui arrivent alors que la précédente est en cours de traitement.

const fetchUserEpic = action$ => 
    action$.ofType(FETCH_USER) 
    .exhaustMap(action => 
     ajax.getJSON(`/api/users/${action.payload}`) 
     .map(response => fetchUserFulfilled(response)) 
     .takeUntil(action$.ofType(FETCH_USER_CANCELLED)) 
    ); 
+0

@jachenry exhaustMap est certainement le plus idiomatique – jayphelps

+0

@jayphelphs Savez-vous s'il y a est un équivalent pour rxjava? Ne s'affiche pas dans les documents. – jachenry

+0

@jachenry il n'y a pas d'équivalent. Aurait besoin d'un opérateur personnalisé. – jayphelps