Ngrx store take(1), but reset after logout/login

641 Views Asked by At

So, imagine you have an ngrx store with a list of books.

When you log in to your profile page you fetch your books using:

this.store.dispatch(getBooks());

Which will trigger the effect:

  getBooks$ = createEffect(() =>                                                                 
    this.actions.pipe(                                                                         
      ofType(A.getBooks),                                                                        
      switchMap(() =>                                                                          
        this.bookService.getBooks().pipe(                                                        
          map((books) => A.getBooksOk({ books })),                                                                                  
          catchError(() => EMPTY),
        ),                                                                                     
      ),                                                                                       
    ),                                                                                         
  ); 

However, you don't want this effect to be triggered every time you navigate to your profile page, since you only need to get the books once.

So you add take(1):

  getBooks$ = createEffect(() =>                                                                 
    this.actions.pipe(                                                                         
      ofType(A.getBooks),
      take(1),                                                                        
      switchMap(() =>                                                                          
        ...

The problem now is that if you log out and then log into another profile the store will not get your books since the effect has already been triggered by the previous profile.

The obvious solution to this would be to not use take(1), and instead have another variable booksLoaded in the store that you can use to check if you should get the books or not.

However, this is quite tedious since you would need one of these 'loaded' variables for each variable in the store, and add a bunch of extra code to manage these variables.

So, the question is: is there a way to make an effect only trigger once (like take(1)), but then when you log out and back in, you allow the effect to trigger again (just once)?

Edit: You could also just check if the books are undefined in the effect. However, the effect could still be triggered multiple times before you get the response from the server, so it would not always work.

1

There are 1 best solutions below

4
Jeff Mercado On

I don't know why you think it's a hassle just to check if you already have data. You don't need a new variable necessarily, just check if your results is already set.

getBooks$ = createEffect(() =>
  this.actions.pipe(
    ofType(A.getBooks),
    withLatestFrom(this.store.select(S.selectBooks)),
    exhaustMap(([, books]) =>
      iif(
        () => books,
        of(A.getBooksOk({ books })),
        this.bookService.getBooks().pipe(
          map((books) => A.getBooksOk({ books })),
          catchError(() => EMPTY),
        ),
      ),
    ),
  ),
);

Just make sure you clear out your books in your reducer where it makes sense (like when you logout).