bertonc96
bertonc96

Reputation: 826

Resubscribe effect after interrupting with takeUntil

I have a NGRX effect inside a feature module that gets lazy loaded when navigating on a certain page. This effect uses an action that is independent from this feature module but that's emitted after some authentication logic from inside another feature module. When exiting from that route I wanted to avoid running that NGRX effect since I have no use to keep subscribing to that event. To do that I used the takeUntil operator in order to unsubscribe the effect after some specific "exit" action, like this:

  afterSomeAuthLogicEffect$ = createEffect(() => this.actions$.pipe(
    ofType(authActions.someLoginSuccess),
    mergeMap(() => {
      return this.myService.doSomethingWhileInThisRoute()
        .pipe(
          map(() => featureModuleActions.ok()),
          catchError((error) => featureModuleActions.error(error))
        );
    }),
    takeUntil(this.actions$.pipe(
      ofType(featureModuleActions.loadExitRoute)
    ))
  ))

After triggering loadExitRoute this method works fine and the effect is no more subscribed.

The issue is that, when I navigate again on the same feature route, the afterSomeAuthLogicEffect is not re-subscribed and it does not re-subscribe to the auth action.

I was expecting that after the navigation the effects would be reinitialized but it seems not.

Is there any way to force the re-subscription of the effect? Maybe I have to re-create the effect inside some specific lifecycle method?

Upvotes: 0

Views: 712

Answers (1)

timdeschryver
timdeschryver

Reputation: 15505

You can use repeat RxJS operators with the delay option (previosly repeatWhen operator) for this task.

Given your example, something like this:

  afterSomeAuthLogicEffect$ = createEffect(() => this.actions$.pipe(
    ofType(authActions.someLoginSuccess),
    mergeMap(() => {
      return this.myService.doSomethingWhileInThisRoute()
        .pipe(
          map(() => featureModuleActions.ok()),
          catchError((error) => featureModuleActions.error(error))
        );
    }),
    takeUntil(this.actions$.pipe(
      ofType(featureModuleActions.loadExitRoute)
    )),
    repeat({
      delay: () => this.actions$.pipe(
        ofType(RELOAD_PAGE_EVENT),
        filter((a) => a.payload.event.url.includes('/YOUR_FEATURE_URL'))
      )
    }),
  ))

This operator allows to resubscribe to a source when the source completes in order to keeping the subscription alive.

Inside the repeat({ delay }) you can return an observable that emits whenever you want to resubscribe after the takeUntil completes the source. In your case you can listen to routes events or any subscribable lifecycle event in order to "reload" the effect.

https://rxjs.dev/api/operators/repeat

Upvotes: 3

Related Questions