EinArzt
EinArzt

Reputation: 367

Cleaner way of subscribing to the actions stream with NGXS

So I'm usually having a method that dispatches an action on click:

create() {
  this.store.dispatch(new Create(this.form.value)); 
}

this code triggers the following scenario and dispatches a CreateSuccess or CreateFailed depending of if the request failed or not

@Action(Create)
create({ dispatch }: StateContext<StateInterface>, { entity}: Create) {
  return this.http.post('mybackend', entity).pipe(
    tap<EntityType>(resp => dispatch(new CreateSuccess(resp))),
    catchError(error => dispatch(new CreateFailed(error)))
  ); 
}

Now inside the Component where I called the create() I'm listening for those two actions.

this.actions$.pipe(
  ofActionSuccessful(CreateSuccess, UpdateSuccess),
  takeUntil(componentDestroyed(this)) // <--
).subscribe(action => doStuff());

This all works flawlessly, the only thing that bothers me is that every time I use this, I have to add the takeUntil() part so the subscription is cancelled when the component is destroyed.

I know this is probably not a real issue for everyone, but I'd like to know if there is a cleaner way to do this.

I've thought about a custom RxJS operator that could handle this, but maybe there are other options, or (something I haven't found anything about), is there a way that NGXS does the unsubscribing itself?

Upvotes: 7

Views: 9474

Answers (2)

Mark Whitfeld
Mark Whitfeld

Reputation: 6848

In NGXS the dispatch method returns an observable that will complete once the action handling is complete (no unsubscribe necessary). So in your example your Create action will complete when the handlers of the action have completed. If a handler returns an observable (like you have done) then the completion is linked to the completion of that observable. If you were to use a map as opposed to a tap for the dispatching of the CreateSuccess action then the originating observable will wait for that 'child' observable to complete first. I would structure the handler like this to make the Create action complete only once the CreateSuccess has completed:

@Action(Create)
create({ dispatch }: StateContext<StateInterface>, { entity}: Create) {
  return this.http.post('mybackend', entity).pipe(
    map<EntityType>(resp => dispatch(new CreateSuccess(resp))),
    catchError(error => dispatch(new CreateFailed(error)))
  ); 
}

Then in your component you can do this:

create() {
  this.store.dispatch(new Create(this.form.value))
    .subscribe(action => doStuff()); 
}

The observable would complete when the dispatched action's handling (and 'child' action handling) is completed. No unsubscription necessary.

Upvotes: 5

kctang
kctang

Reputation: 11202

NGXS does not provide any special features to unsubscribe based on Angular component's lifecycle.

Generally, unsubscribing when a component is destroyed make sense. However, there are scenarios where you want more specific control when to subscribe/unsubscribe.

So, you will have to manage it in every Angular component's appropriate lifecycle functions.

Upvotes: 0

Related Questions