Search code examples
angularrxjsngrx

Angular effect to update state from localstorage on successful fetch


I wrote the following effect to listen in on a successful fetch on a page and update state from local storage:

export const updateStateFromTokensEffect = createEffect(
  (actions$ = inject(Actions), jwtService = inject(JwtHelperService)) => {
    return actions$.pipe(
      ofType(FeedActions.fetchSuccess),
      tap(() => {
        const token = localStorage.getItem('token');
        const {
          sub: userId,
          username,
          email,
          image,
        } = jwtService.decodeToken(token!);
        return AuthActions.loginSuccess({
          user: {
            userId,
            username,
            email,
            image,
          },
        });
      })
    );
  },
  {
    functional: true,
  }
);

I initially wanted to add this logic to my route guards but decided against it. Needless to say, it doesn't work as expected and even prevents the loading of the page which is made possible by the following effect:

export const feedEffect = createEffect(
  (actions$ = inject(Actions), feedService = inject(FeedService)) => {
    return actions$.pipe(
      ofType(FeedActions.fetch),
      switchMap(() => {
        return feedService.fetchArticles().pipe(
          map((articles: ArticleInterface[]) => {
            return FeedActions.fetchSuccess({ articles });
          }),
          catchError(() => {
            return of(FeedActions.fetchFailure());
          })
        );
      })
    );
  },
  { functional: true }
);

I have route guards in place that only load routes if theres a valid token in state. In this token are the user's info so I'd like some way to populate certain elements on every page based on the user's info. For this, I need it to be added to my global state on every successful page load (every page that's not an auth page).

Is this approach bad? Does anyone know why the first effect is breaking the second? Any help is much appreciated as usual

Side note: my inclination is that the effect is somehow messing up the flow of the FeedActions.fetchSuccess but I'm not sure, rxjs ops are tricky


Solution

  • If i'm not wrong tap operator is used for side effects, not to modify the data stream itself. you're returning AuthActions from tap(), I don't think that's the proper way of using tap(). Can you try using map() or swithMap() see if it's solve your problem ? let me know. You can read more here

    The tap operator is often used for debugging, logging, or performing any action that doesn’t change the emitted values in the observable stream. It’s particularly useful when you want to inspect the values, perform side effects, or trigger actions without altering the data flow.