web-dev-qa-db-fra.com

Annuler les demandes précédentes et ne déclencher que la dernière demande avec redux observable

J'ai donc un cas d'utilisation où je mets à jour la demande d'api lorsque la carte est déplacée - mais cela pourrait générer plusieurs demandes de tir rapides avec de petits mouvements de carte - et je veux annuler toutes les demandes en vol sauf la dernière. Je peux utiliser debounce pour envoyer uniquement des demandes après un délai. Cependant, je veux toujours annuler toutes les anciennes demandes si elles sont toujours en cours.

const fetchNearbyStoresEpic = action$ =>
  action$.ofType(FETCH_NEARBY_STORES)
    .debounceTime(500)
    .switchMap(action =>
      db.collection('stores')
        .where('location', '<=', action.payload.max).
        .where('location', '>=', action.payload.min)
        .map(response => fetchNearbyStoresFulfilled(response))
        .takeUntil(action$.ofType(FETCH_STORES_CANCELLED))
    );

Je vois que vous pouvez utiliser takeUntil mais vous devez déclencher explicitement une action d'annulation. Je vois dans les documents que switchMap prendra la dernière et annulera tous les autres - dois-je implémenter une interface d'annulation dans mon appel api? Dans ce cas, ce serait une requête Firebase pour Firestore.

8
MonkeyBonkey

D'un commentaire que j'ai fait dans un problème GitHub:

Parce qu'ils ont une dimension temporelle, il existe plusieurs stratégies d'aplatissement pour les observables:

  • Avec mergeMap (qui a flatMap comme alias), les observables reçus sont abonnés simultanément et leurs valeurs émises sont aplaties dans le flux de sortie.
  • Avec concatMap, les observables reçus sont mis en file d'attente et sont abonnés les uns après les autres, à mesure que chacun se termine. (concatMap est mergeMap avec une concurrence d'un.)
  • Avec switchMap, lorsqu'un observable est reçu, il est abonné et tout abonnement à un observable précédemment reçu est désabonné.
  • Avec exhaustMap, lorsqu'un observable est reçu, il est souscrit sauf s'il existe un abonnement à un observable précédemment reçu et que cet observable n'est pas encore terminé - auquel cas l'observable reçu est ignoré.

Ainsi, comme Mark l'a dit dans sa réponse, lorsque switchMap reçoit une action ultérieure, il se désabonne de toute demande incomplète.

Cependant, la demande ne sera pas annulée jusqu'à ce que l'action rejetée atteigne le switchMap. Si vous souhaitez annuler toute demande en attente immédiatement lors d'un autre déplacement - plutôt que d'attendre la durée du rebounce - vous pouvez utiliser takeUntil avec l'action FETCH_NEARBY_STORES:

const fetchNearbyStoresEpic = action$ =>
  action$.ofType(FETCH_NEARBY_STORES)
    .debounceTime(500)
    .switchMap(action =>
      db.collection('stores')
        .where('location', '<=', action.payload.max).
        .where('location', '>=', action.payload.min)
        .map(response => fetchNearbyStoresFulfilled(response))
        .takeUntil(action$.ofType(FETCH_NEARBY_STORES))
    );

Cela devrait entraîner la désinscription immédiate d'une demande lors d'un autre déménagement. (Du haut de ma tête, je ne me souviens pas du comportement de action$ Dans redux-observable. Il est possible que vous deviez ajouter une skip(1) à l'observable passé à takeUntil. Essayez et voyez.)

Et, comme Mark l'a mentionné, cela dépend de l'implémentation sous-jacente qui annule la demande lors de la désinscription.

12
cartant

switchMap abandonnera sa précédente observable lorsqu'une nouvelle émission est envoyée à travers elle. Selon votre bibliothèque HTTP sous-jacente et si elle prend en charge l'annulation (compatible avec l'observable), cela devrait suffire.

Étant donné qu'aucun détail d'implémentation n'a été fourni dans votre question, vous devrez examiner fetchNearbyStoresFulfilled pour voir s'il utilise un client http compatible avec Observable. S'il utilise en interne des promesses, aucun support d'annulation n'est fourni.

4