0

In the following epic I am listening to an action$ stream and then also listening to an auth stream authState(app.auth())

export const fetchAuthStatus = action$ =>
      action$.pipe(
        ofType(AUTH_STATUS_CHECKED),
        switchMap(() => authState(app.auth())),
        switchMap(user =>
          user
            ? of({ type: 'SIGNED_IN', payload: user })
            : signIn(googleAuthProvider)
        ),
        catchError(error => console.log('problems signing in'))
      );

It works as expected, the only problem is that if I change the auth status by logging out then the epic fires the signIn() method since useris no longer available.

How do I stop listening to authState(app.auth()) once I have signed in. Where does the unsubscribe logic go in an epic?

Josh Pittman
  • 7,024
  • 7
  • 38
  • 66
  • Could you just take the first element from `authState(app.auth())` by applying the operator `take(1)` on the returned Observable? I.e. ```switchMap(() => authState(app.auth()).pipe(take(1))),``` – Harald Gliebe Mar 30 '19 at 18:34
  • Thank you. So adding take(1) works well for the first time I login, but if I logout and then try and log back in nothing. – Josh Pittman Mar 31 '19 at 03:21
  • I assumed that there would have been another `AUTH_STATUS_CHECKED` action when you re-login. The new action would then have started a new `authState(app.auth()) observable in the `switchMap`. But if the `AUTH_STATUS_CHECKED` action is triggered only once, this won't work of course. Could you describe a bit more how your login/logout process should work? – Harald Gliebe Mar 31 '19 at 06:53
  • I wanted a button to log people in and then another button to log people out. that's pretty much it. The if/else above is because the login button either logs you in or shows you an 0Auth modal depending on whether you have an already authenticated this session. For example, if you log in and then refresh the page, you dont need to log in again, it knows the session is valid. – Josh Pittman Mar 31 '19 at 07:52
  • I think, you have two logical actions in one here. One should check authorisation on page load, the other should react on login button. Split that into two and you'll get what you need – kos Mar 31 '19 at 09:34
  • (imho, action on the login button click could be split as well. So at the end you get 3 actions: 1. check auth at app start, 2. login user 3. OAuth for logged in user) – kos Mar 31 '19 at 09:37

1 Answers1

1

Epics are supposed to stay alive as long as your app is running.

You don't complete them, you mute them.

To mute a stream there are a lot of possibilities. For example, windowToggle operator will let you mute your observable by another streams, say, by streams of other events.

E.g. you mute the epic while in-between SIGN_INSIGN_OUT sequence. And unmute in SIGN_OUTSIGN_IN period.

Heres an article on different pausing strategies with rxjs.

Hope this helps

kos
  • 5,044
  • 1
  • 17
  • 35
  • Thanks Kos, so how would I mute this specific example? – Josh Pittman Mar 31 '19 at 03:01
  • And when you say epics always run does that mean redux-observables handles unsubscribing when the app unmounts? If not won't thise lead to a memory leak? – Josh Pittman Mar 31 '19 at 03:02
  • 1
    @JoshPittman, well, its a responsibility of the library to init completion of the `action$` stream. You don't have yo worry about that. – kos Mar 31 '19 at 09:40