2017-10-12 5 views
0

J'essaie de créer une épique qui met en file d'attente les actions à distribuer, dans ce cas, les actions sont des messages à afficher avec un snack. trois erreurs sont survenues presque simultanément, et je veux afficher les trois messages d'erreur avec un SnackBar, l'Epic devrait envoyer une action pour afficher le premier pendant 3 secondes, puis afficher le second pendant 3 secondes puis le troisième pendant 3 secondes .Comment faire pour mettre en file d'attente les actions correctement dans le temps lors de l'utilisation de redux-observables

De plus, si l'un des casse-tête se ferme, le deuxième dans la «file d'attente» devrait s'afficher et ainsi de suite. Ce que je fais en ce moment, c'est envoyer l'action qui affiche le message dans Epics qui attrape les erreurs, puis je crée Epics envoyer l'action pour fermer le snack après 3 secondes de retard, avec l'action CLOSE_SNACKBAR. Quelles méthodes dois-je utiliser pour y parvenir? Une épique de base que j'ai implémentée ressemble à ceci, fondamentalement l'action qui change l'état du snack pour ouvrir et affiche le message d'erreur est expédiée à partir d'une autre épopée, celle qui attrape l'erreur, puis un autre dépêche épique l'action de fermer le snack après 3 secondes, mais je n'ai pas compris comment faire cette sorte d'action de sorte que chaque message peut être affiché pendant 3 secondes chacun, maintenant si une erreur se produit juste après le premier, le le deuxième message sera affiché sans attendre les 3 secondes après le message précédent. Voici quelques exemples de base de mes épopées (Ignorer partie de la demande,):

const getUserEpic = (action$, store) => (
    action$.ofType(actionTypes.DATA_REQUESTED) 
     .switchMap(action => { 
      const { orderData, queryData, pagerData } = store.getState().usuario.list; 
      const params = constructParams(queryData, pagerData, orderData); 
      return Observable.defer(() => axios.get(`users`, { params })) 
       .retry(NETWORK.RETRIES).mergeMap(response => { 
         Observable.of(actions.dataRequestSucceeded(response.data.rows)) 
       }).catch(error => Observable.concat(
        Observable.of(actions.dataRequestFailed(error)), 
        Observable.of({ 
         type:'DISPLAY_DATA_REQUEST_FAILED_MESSAGE', 
         open:true, 
         message:'Failed to get Users Data' 
        }) 
      )); 
     }) 
) 
const getRoleEpic = (action$, store) => (
    action$.ofType(actionTypes.DATA_REQUESTED) 
     .switchMap(action => { 
      const { orderData, queryData, pagerData } = store.getState().usuario.list; 
      const params = constructParams(queryData, pagerData, orderData); 
      return Observable.defer(() => axios.get(`role`, { params })) 
       .retry(NETWORK.RETRIES).mergeMap(response => { 
         Observable.of(actions.dataRequestSucceeded(response.data.rows)) 
       }).catch(error => Observable.concat(
        Observable.of(actions.dataRequestFailed(error)), 
        Observable.of({ 
         type:'DISPLAY_DATA_REQUEST_FAILED_MESSAGE', 
         open:true, 
         message:'Failed to get Roles Data' 
        }) 
      )); 
     }) 
) 

Ces deux épopées font essentiellement le seme, ils font une demande GET au backend, mais si elles échouent, ils envoient l'action qui ouvre le snack avec un message d'erreur, et les deux messages d'erreur sont différents.

Et celui-ci est l'épopée qui ferme actuellement au bout de 3 secondes Snack-bar:

const displayDataRequestFailedEpic = (action$, store) => (
    action$.ofType(actionTypes.DISPLAY_DATA_REQUEST_FAILED) 
     .debounceTime(3e3) 
     .switchMap(action => { 
      return Observable.of({ 
       type:'CLOSE_SNACKBAR', 
       open:false, 
       message:'' 
      }) 
     }) 
) 

Imaginez que je fais les demandes très vite et les deux d'entre eux échouent. Je veux montrer toutes les erreurs qui se sont produites, l'un après l'autre pendant 3 secondes chacun,

+0

Pouvez-vous reformuler/élaborer un peu plus sur ce que vous demandez? – jayphelps

+0

J'ai réélaboré la question, j'espère que le problème est plus clair maintenant – sgaseretto

Répondre

0

Cela n'a pas été testé ...

Tout d'abord, besoin de séparer l'action qui affiche des messages de l'action qui est à l'origine l'affichage:

const getUserEpic = (action$, store) => (
    action$.ofType(actionTypes.DATA_REQUESTED) 
     .switchMap(action => { 
      const { orderData, queryData, pagerData } = store.getState().usuario.list; 
      const params = constructParams(queryData, pagerData, orderData); 
      return Observable.defer(() => axios.get(`users`, { params })) 
       .retry(NETWORK.RETRIES).mergeMap(response => { 
         return Observable.of(actions.dataRequestSucceeded(response.data.rows)) 
       }).catch(error => Observable.of(actions.dateRequestFailed(error)) 

       // }).catch(error => Observable.concat(
       //  Observable.of(actions.dataRequestFailed(error)), 
       // 
       // this will be handled elsewhere 
       // 
       //  Observable.of({ 
       //   type:'DISPLAY_DATA_REQUEST_FAILED_MESSAGE', 
       //   open:true, 
       //   message:'Failed to get Users Data' 
       //  }) 
      )); 
     }) 
) 

prochaine, le besoin de définir une méthode qui crée l'action DISPLAY_MESSAGE de toute action est le déclenchement du message. Inclus dans l'action devrait être un identifiant unique utilisé pour suivre quel message doit être fermé.

Enfin, utilisez concatMap() pour créer et détruire les messages.

const displayEpic = action$ => action$ 
    .ofType(actionTypes.DATA_REQUEST_FAILED) 
    .concatMap(action => { 
    const messageAction = actions.displayMessage(action); 
    const { id } = messageAction; 
    return Rx.Observable.merge(
     Rx.Observable.of(messageAction), 
     Rx.Observable.of(actions.closeMessage(id)) 
     .delay(3000) 
     .takeUntil(action$ 
      .ofType(actionTypes.CLOSE_MESSAGE) 
      .filter(a => a.id === id)) 
    ); 
    });