| Среда, 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. Но все равно, за исключением этото недостатка, количество переменных за которыми нужно приглядывать уменьшилось.
Но на самом деле, если совсем нет потребности в явной подписке на 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-2025 (v2.4.7 - работает на Angular Universal)Калькулятор инвест-портфеля