Управление подписками в Angular
Development, Java | Комментировать запись
Встроенный асинхронный конвейер в Angular 2+ — это отличный инструмент для управления наблюдаемыми подписками. С его помощью в большинстве случаев можно избежать ручной подписки на наблюдаемые объекты в классах компонентов.
Допустим, мы хотим получить наблюдаемый объект, который каждую секунду выдает нам текущее время. Без асинхронного конвейера мы могли бы сделать что-то вроде этого:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/map';
@Component({
selector: 'app-root',
template: `Time: {{ time | date:'mediumTime' }}`
})
export class AppComponent implements OnInit, OnDestroy {
time: Date;
timeSub: Subscription;
ngOnInit() {
this.timeSub = Observable
.interval(1000)
.map(val => new Date())
.subscribe(val => this.time = val);
}
ngOnDestroy() {
this.timeSub.unsubscribe();
}
}
В хуке OnInit мы создали наблюдаемый объект, который каждую секунду генерирует значение и сопоставляет его с новой датой. Затем мы подписались на этот наблюдаемый объект и установили выдаваемое значение для переменной класса времени. Мы также позаботились о том, чтобы вовремя отказаться от подписки на наблюдаемый объект, когда компонент будет уничтожен.
В шаблоне мы использовали встроенный канал даты, чтобы преобразовать дату в желаемый формат (минуты и секунды).
Однако у нас получилось довольно много шаблонного кода, а еще мы рискуем создать утечку памяти, если забудем своевременно отказаться от подписки. Этот код можно значительно упростить. Вот те же функции, но реализованные с помощью асинхронного конвейера:
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/map';
@Component({
selector: 'app-root',
template: `Time: {{ time$ | async | date:'mediumTime' }}`
})
export class AppComponent {
time$ = Observable
.interval(1000)
.map(val => new Date());
}
Асинхронный конвейер управляет подпиской и разворачиванием данных, а также отменяет подписку при уничтожении компонента.
Мы также можем использовать асинхронный конвейер для развертывания и передачи данных на вход для дочернего компонента:
<app-child [time]="time$ | async"></app-child>
И теперь дочернему компоненту нужно только отобразить данные.
Директива ngFor
Допустим, у нас есть немного более сложная структура данных, доступная как observable, и мы установили искусственную задержку в 1 секунду перед получением ее значения (имитируя сетевой запрос):
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/delay';
@Component({ ... })
export class AppComponent {
cities$ = Observable
.of([
{name: 'Los Angeles', population: '3.9 million', elevation: '233′'},
{name: 'New York', population: '8,4 million', elevation: '33′'},
{name: 'Chicago', population: '2.7 million', elevation: '594′'},
])
.delay(1000);
}
В шаблоне мы можем развернуть и подписаться на данные (когда они поступят) с помощью директивы ngFor:
<ul>
<li *ngFor="let city of cities$ | async">
Name: {{ city.name }},
Population: {{ city.population }},
Elevation: {{ city.elevation }}</li>
</ul>
Директива ngIf
Вот пример использования структурной директивы ngIf. Наш observable выглядит так:
word$ = Observable.of('Abibliophobia');
А шаблон – так:
<span *ngIf="(word$ | async)?.length > 9; else shortWord">
Long word: {{ word$.value }}
</span>
<ng-template #shortWord>
Short word: {{ word$.value }}
</ng-template>
В результате мы получим:
Long word: Abibliophobia
Обратите внимание: мы передаем observable word$ через async, но заключаем его в круглые скобки, чтобы затем можно было проверить длину развернутого значения. Мы также используем оператор ?, чтобы избежать ошибки, когда значение word$ еще не доступно.
Читайте также: Управление подпиской RxJS с помощью takeUntil
Tags: Angular, AngularJS