Home > other >  Why is this live observable triggering and how do I stop it?
Why is this live observable triggering and how do I stop it?

Time:11-24

I recently changed my DB method to get a user as a live observable instead of a promise. Prior to that I had a separate action to re-load the user if a field was changed through the UI. The live observable works really well as changes to the DB are instantly reflected in the app. Unfortunately this broke my logout button and I don't understand why nor how to fix it.

Auth service that triggers DB loading of user

this.afAuth.authState.subscribe((user) => {
  if (user) {
    const appUser: AuthUser = {
      uid: user.uid,
      name: user.displayName,
      photoURL: user.photoURL,
    };
    this.store.dispatch(userActions.loggedIn({ user: appUser }));
  } else {
    this.store.dispatch(userActions.logout());
  }
});

Relevant actions

loggedIn: createAction('[User] Logged in', props<{ user: AuthUser }>()),
userLoaded: createAction('[User] User loaded', props<{ dbUser: DbUser }>()),
logout: createAction('[User] Logout'),

Action responsible to update state

getDbUser = createEffect(() =>
  this.actions$.pipe(
    ofType(userActions.loggedIn),
    switchMap(({ user: { uid } }) =>
      this.databaseService.getUser(uid).pipe( // <- this only correctly fires once
        map((dbUser) => userActions.userLoaded({ dbUser })), // <- this fires after the logout action and I don't know why
        // first() <- this solves the logout issue but breaks the live updates
      )
    )
  )
);

Get a live connection with AngularFire

getUser(uid: AppUser['uid']): Observable<DbUser> {
  return this.afs
    .collection<DbUser>(constants.dbCollections.users)
    .doc(uid)
    .snapshotChanges()
    .pipe(map((action) => action.payload.data()));
}

Reducer

// Login
on(userActions.loggedIn, (state, payload) => ({
  ...initialState,
  user: payload.user,
})),
on(userActions.userLoaded, (state, payload) => ({
  ...state,
  user: {
    ...payload.dbUser,
    roles: new Set(payload.dbUser?.roles),
    licenses: new Set(payload.dbUser?.licenses),
  },
})),
on(userActions.logout, (state) => ({ ...initialState })),

Why does userActions.userLoaded({ dbUser }) keep firing? No user data is modified in the DB upon logout.
How do I stop it from firing after the logout action?

CodePudding user response:

Without more code, it's difficult to understand it correctly.

You probabably need to unsubscribe to this.actions$ after logout and subscribe in the login

CodePudding user response:

I found one way to fix it.

getUser(uid: AppUser['uid']): Observable<DbUser> {
  return this.afs
    .collection<DbUser>(constants.dbCollections.users)
    .doc(uid)
    .snapshotChanges()
    .pipe(
      map((action) => action.payload.data()),
      takeUntil(this.afAuth.authState.pipe(first((x) => !x))) // Fix
    );
}

When I add a dependency on AngularFireAuth in my database service I can use takeUntil in the getUser method. I'm not sure how I feel about the dependency though, if there is a cleaner more decoupled solution that would still be welcome.

  • Related