Search code examples
javascriptreduxrxjsredux-observable

How can I chain RxJS observable in a redux-observable epic?


I've just started learning redux-observables and RxJS for work recently. We have alerts globally set in Redux. I want to be able to set an alert, then after a set period, close that same alert. There can also be multiple alerts at any time, and the user could manually close one alert before it automatically closes itself. I have added to id here, so I can close the correct alert. I have attempted to use delay after the initial map than another map to achieve this so far. However, this skips the first map.

export const addAlertEpic: Epic<Action, Action, RootState> = (
  action$,
  state$
) =>
  action$.pipe(
    ofType(slice.actions.addAlert),
    map((values: any) =>
      slice.actions.addAlertSuccess({ id: uuid(), ...values.payload })
    )
  );

Thank you for help!


Solution

  • set an alert, then after a set period, close that same alert [...] he user could manually close one alert before it automatically closes itself

    With that in mind, here would be my approach:

    actions$.pipe(
      ofType(slice.actions.addAlert),
    
      // `There can also be multiple alerts at any time`
      mergeMap(action => {
        const id = uuid();
    
        // using `NEVER` is important, it's essentially the same as new Observable(() => {})
        // it is needed because we don't want the inner observable to complete unless `takeUntil` decides to
        return NEVER
          .pipe(
    
            // start with opening the alert
            startWith(slice.actions.addAlertSuccess({ id, ...action.payload }))
            
            // close the alert either
            takeUntil(merge(
              
              // when `TIME` expires
              timer(TIME),
              
              // or when the user decides to
              userClosedActions.pipe(
                filter(action => action.id === id)
              )
            )),
    
            // at the end(when the stream completed due to `takeUntil`), close the alert
            endWith(slice.actions.closeAlertSuccess(...))
          )
      })
    )
    

    userClosedActions can be a Subject that sends next notifications as a result of user action. For example:

    onClick (closedId) {
     userClosedActions.next({ id: closedId })
    }