Избыточный код: RXJS — уменьшаем количество отписок от Observable-переменных

| Среда, 26 февраля, 2020

Метки: Angular, RxJS Комментарии: 0

Часто, например, реализовывая обмен данными между компонентами приходится создавать сервисы c observable переменными. Допустим, для того, чтобы изменения данных из одного компонента мы мгновенно получали в другом компоненте.

Одним из неудобств является то, что подписанное изменение нужно сохранить в объект Subscription и потом не забыть отписаться от него. Иначе это может привести в неожиданному поведению и багам, которые потом не всегда понятно из-за чего происходят.

@Component({
    selector: 'app-test',
    template: `
      <div>{{data1}}</div>
      <div>{{data2}}</div>
    `,
})
export class TestComponent implements OnInit, OnDestroy {
    subs: Subscriptions = {};
    data1: string;
    data2: number;
    constructor(private testService: TestService) {
    }
    ngOnInit(): void {
        this.subs.data1 = this.testService.data1$.subscribe(data1 => {
            this.data1 = data1;
        });
        this.subs.data2 = this.testService.data2$.subscribe(data2 => {
            this.data2 = data2;
        });
    }
    ngOnDestroy(): void {
        SubscriptionsHelper.unsubscribe(this.subs);
    }
}

Если такая ситуация очень часто встречается в проекте, как вариант, можно добавить в общие файлы проекта класс со статичным методом, который аккумулирует такие подписки, и потом разом от них отписывается, Это вполне удобно, чтобы не следить для чего уже добавлена отписка, а для чего еще нет.

import {Subscription} from 'rxjs';
export interface Subscriptions {
    [key: string]: Subscription;
}
export class SubscriptionsHelper {
    static unsubscribe(subscriptions: Subscriptions) {
        Object.keys(subscriptions).forEach(key => {
            if (subscriptions[key]) {
                subscriptions[key].unsubscribe();
                delete subscriptions[key];
            }
        });
    }
}

И тогда исхлодный код самого первого примера можно оформить так:

export class TestComponent implements OnInit, OnDestroy {
    subs: Subscriptions = {}; // здесь меньше
    data1: string;
    data2: number;
    constructor(private testService: TestService) {
    }
    ngOnInit(): void {
        this.subs.data1 = this.testService.data1$.subscribe(data1 => {
            this.data1 = data1;
        });
        this.subs.data2 = this.testService.data2$.subscribe(data2 => {
            this.data2 = data2;
        });
    }
    ngOnDestroy(): void {
        SubscriptionsHelper.unsubscribe(this.subs); // здесь меньше
    }
}
Вроде все нормально, если бы не маленький нюанс, при сохранении подписок все равно нужно следить, чтобы свойства объекта subs не совпали: this.subs.data1 и this.subs.data2. Иначе объект подписки перезатрется и потом его уже SubscriptionHelper не отпишет в ngOnDestroy. Но все равно, за исключением этото недостатка, количество переменных за которыми нужно приглядывать уменьшилось.

Более красивое решение из фреймворка Angular

Но на самом деле, если совсем нет потребности в явной подписке на observable-переменную в компоненте, то можно обойтись и более компактным решением, для этого нам поможет специальный пайп(pipe) async, который мы можем применить прямо в шаблоне компонента.

Еще больше зачищаем код исходного компонента, оставляя лишь сами observable-переменные.

@Component({
    selector: 'app-test',
    template: `
      
{{data1$ | async}}
{{data2$ | async}}
`, }) export class TestComponent implements OnInit { data1$: Observable; data2$: Obsevable; constructor(private testService: TestService) { } ngOnInit(): void { this.data1$ = this.testService.data1$; this.data2$ = this.testService.data2$; } }

Итого, первоначальный вариант нашего компонента сократился почти в два раза, но не это главное. Главное, что он стал более читабельным и рафинированным, в котором отображена самая главная суть.

На небольшом примере — мы получили небольшой профит, но на крупных проектах, вы сэкономите большие объемы сил и времени, выполняя требуемую функциональность приложений, не делая лишних движений и не запутывая самих же себя.

Комментарии
Никто еще не оставил здесь комментарий.
Войдите, чтобы написать комментарий , или воспользуйтесь формой ниже.
 

Copyright © CodeHint.ru 2013-2020