rxjs

What is the purpose of RxJs Subscription and unsubscribe when it not needed?


I have seen the following code in an angular application. In the code, a Subscription is being used to subscribe and unsubscribe. I don't understand why a Subscription is used. Is there any benefit in using this pattern?

public routeChangeSub$: Subscription;

this.routeChangeSub$ = this.route.firstChild.paramMap
        .subscribe((map: ParamMap) =>
          this.getRouteParams(map));

this.routeChangeSub$.unsubscribe();

getRouteParams(map: ParamMap): number {
    const characterId = map.get('id');
    let id: number = null;
    if (characterId) {
      this.character$ = this.store.pipe(
        select(selectCharacterById, { id: characterId })
      );
      id = parseInt(characterId, 10);
    }
    return id;
  }

Update:

How this can be different from

this.route.firstChild.paramMap
        .subscribe((map: ParamMap) =>
          this.getRouteParams(map));

getRouteParams(map: ParamMap): number {
    const characterId = map.get('id');
    let id: number = null;
    if (characterId) {
      this.character$ = this.store.pipe(
        select(selectCharacterById, { id: characterId })
      );
      id = parseInt(characterId, 10);
    }
    return id;

Solution

  • An observable (which is the type of route.firstChild.paramMap) will not emit anything unless something is subscribed to it.

    In this file, the author explicitly subscribes to paramMap to trigger a state change by calling getRouteParams(). Then they immediately unsubscribe. If they didn't unsubscribe, the subscription will continue to run which may cause state issues and memory leaks.

    A far simpler solution is to use the take(1) operator. This will take an emitted value (the 1 is the number of values to take) then will send a complete signal to the subscription. This causes the subscription to automatically unsubscribe.

    this.route.firstChild.paramMap.pipe(
      take(1),
      tap(map=>this.getRouteParams(map))
    ).subscribe();
    

    Because we're using take(), we don't need to assign the subscription to a property. The observable will emit one value, and will invoke getRouteParams() before unsubscribing.

    Note: If you're not aware, tap() is the operator to use if you want to apply an effect to any state property outside of the observable.