web-profile

Unsubscribe Angular Observable

The component will get destroyed but the subscription will live on. So unsubscribed observable may create a memory leak.

The .unsubscribe() Method

@Component({...})
export class CustomComponent implements OnInit, OnDestroy {
    private sub1: Subscription;
    private sub2: Subscription;

    constructor(private httpService: HttpClient) {}

    ngOninit(): void {
        this.sub1 = this.httpService.get('custom-url.com')
                .pipe(takeUntil(this.unsubscribe$))
                .subscribe((values) => {
                    // Do something with the data
                })
        
        this.sub2 = this.httpService.get('other-url.com')
                .pipe(takeUntil(this.unsubscribe$))
                .subscribe((values) => {
                    // Do something with the data
                })
    }

    ngOnDestroy(): void {
        this.sub1?.unsubscribe();
        this.sub2?.unsubscribe();
    }
}

Async Pipe

"| async" the async pipe offers you to handle Observables in your HTML template. The async pipe automatically runs the unsubscribe process after the destruction process of a component.

@Component({
    selector: 'custom-component',
    template: `
        <h1>{{pageTitle$ | async}}</h1>
    `
    ...
})
export class CustomComponent implements OnInit {
    private pageTitle$: Observable<string>;
    constructor(private httpService: HttpClient) {}
    ngOninit(): void {
        this.pageTitle$ = this.httpService.get('custom-url.com')
    }
}

Or you can use it for values that are Objects or Arrays.

@Component({
    selector: 'custom-component',
    template: `
        <ul>
            <li *ngFor="let item of todoList$ | async">{{item?.name}}</li>
        </ul>
    `
    ...
})
export class CustomComponent implements OnInit {
    private todoList$: Observable<string>;
    constructor(private httpService: HttpClient) {}
    ngOninit(): void {
        this.todoList$ = this.httpService.get('other-url.com')
    }
}

Or you can reuse async value.

@Component({
    selector: 'custom-component',
    template: `
        <ng-contatine *ngIf="data$ | async as data">
            {{ data?.title }}
            <div *ngFor="let item of data?.list">{{ item?.name }}</div>
        </ng-contatine>
    `
    ...
})
export class CustomComponent implements OnInit {
    private data$: Observable<string>;
    constructor(private httpService: HttpClient) {}
    ngOninit(): void {
        this.data$ = this.httpService.get('url.com')
    }
}

Advanced way:

{{ (data$ | async)?.title }}

Observables With takeUntil Method

@Component({...})
export class CustomComponent implements OnInit, OnDestroy {
    private unsubscribe$ = new Subject<void>();
    constructor(private httpService: HttpClient) {}

    ngOninit(): void {
        this.httpService.get('custom-url.com')
                .pipe(takeUntil(this.unsubscribe$))
                .subscribe((values) => {
                    // Do something with the data
                })
        
        this.httpService.get('other-url.com')
                .pipe(takeUntil(this.unsubscribe$))
                .subscribe((values) => {
                    // Do something with the data
                })
    }

    ngOnDestroy(): void {
        this.unsubscribe$.next();
        this.unsubscribe$.complete();
    }
}

The ngOnDestroy() method is called before a component is going to be destroyed. In this method, we call two methods.
The next() will pass an empty value to the subscription. With the complete(), we tell the subscription it's done listening for new values.
Now we don’t have to worry about making one or a lot more requests via the HttpClient; we can stop them all at once.

Sources:

Leave a Reply

Your email address will not be published.