我有两个组件:NewItemComponent和ListComponent。当我在相应的组件内创建新项目时,我会通知ListComponent以便它可以刷新其数据模型:
export class NewItemComponent implements OnInit {
constructor(private itemService: ItemService, private notificationService: NotificationService) {
}
ngOnInit() {
}
createNewItem(item: Item) {
this.itemService.persist(item).subscribe((response: Item) => {
console.log(response);
this.notificationService.notifyNewItemHasBeenCreated(response);
});
}
}
export class ListComponent implements OnInit {
items: Item[];
constructor(private listService: ListService, private notificationService: NotificationService) {
}
ngOnInit() {
this.loadItems();
this.notificationService.item$.subscribe((item) => {
if (item != null) {
this.loadItems();
}
})
}
loadItems(){
this.istService.getItems().subscribe((data: Item[]) => {
this.items= data;
console.log(this.items);
});
}
}
@Injectable({
providedIn: 'root'
})
export class NotificationService {
private _item: BehaviorSubject<Item> = new BehaviorSubject<Item>(null);
public item$ = this._item.asObservable();
constructor() {
}
notifyNewItemHasBeenCreated(item: Item) {
this._item.next(item);
}
}
让我担心的是 loadItems()多次调用 subscribe()。可以吗?还是有更好的方法根据通知重新获取项目?
loadItems(){
this.listService.getItems().subscribe((data: Item[]) => {
this.items= data;
console.log(this.items);
});
}
ListService返回Observable:
export class ListService {
basePath = 'my-api.com';
apiPath = "item";
constructor(private httpClient: HttpClient) {
}
getItems(): Observable<Item[]> {
return this.httpClient.get<Item[]>(this.basePath + '/' + this.apiPath);
}
}
提前感谢,我们将不胜感激。
答案 0 :(得分:3)
作为实验,请执行以下操作:
this.httpClient.get("<some url>")
.subscribe({
next: () => {
console.log("received response")
},
error: err => {
console.log("error occurred")
},
complete: () => {
console.log("subscription completed")
},
})
您应该看到:
received response
subscription completed
这意味着每个Web请求的可观察对象在请求完成后即已完成,因此可以安全地取消订阅,因为这是在可观察对象完成时自动完成的。
答案 1 :(得分:1)
编辑:
环顾四周后,我发现了这些帖子:
Is it necessary to unsubscribe from observables created by Http methods?
Prevent memory leaks in Angular 2?
评论和答案说明HttpClient.get()
个订阅会在自己清除后清除,因此您无需退订。这意味着多次调用.subscribe()
很好。
答案 2 :(得分:1)
loadItems()
仅调用一次subscribe
。
实际上发生的是,您在loadItems()
的订阅中多次致电notificationService.item$
。
如果仅出于此目的需要NotificationService
,建议您进行少量重构。
new-item.component.ts
export class NewItemComponent {
constructor(private itemService: ItemService, private listService: ListService) {
}
createNewItem(item: Item) {
this.itemService.persist(item).subscribe((response: Item) => {
this.listService.addItem(item);
});
}
}
list.service.ts
export class ListService {
basePath = 'my-api.com';
apiPath = 'item';
private itemsSubject: BehaviorSubject<Item[]> = new BehaviorSubject<Item[]>([]);
private items$: Observable<Item[]>;
constructor(private httpClient: HttpClient) {
}
getItems(): Observable<Item[]> {
const http$ = this.httpClient.get<Item[]>(this.basePath + '/' + this.apiPath);
return combineLatest(http$, this.items$).pipe(
map(([httpResponse: Item[], localItems: Item[]]) => httpResponse.concat(localItems)),
);
}
addItem(item: Item) {
this.itemsSubject.next([...this.itemsSubject.value, item]);
}
}
答案 3 :(得分:0)
如果您多次订阅呼叫,则在销毁组件时取消订阅。
要像这样更改组件:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
export class ListComponent implements OnInit, OnDestroy {
items: Item[];
constructor(private listService: ListService, private notificationService: NotificationService) {
}
subscriptions: Subscription[] = [];
ngOnInit() {
this.subscriptions.push(this.loadItems());
this.subscriptions.push(this.notificationService.item$.subscribe((item) => {
if (item) {
this.loadItems();
}
}));
}
ngOnDestroy() {
this.subscriptions.forEach(x => x.unsubscribe());
}
loadItems(){
this.istService.getItems().subscribe((data: Item[]) => {
this.items= data;
console.log(this.items);
});
}
}
答案 4 :(得分:0)
您现在正在做的是:
因此,简而言之,您对每个新项目都会向服务器发出2个请求,并获得2个响应。
您可以看到这里有很多冗余。让我们尝试简化一下事情:
现在,您每次只发出一个请求,而不是两个。而且您不再需要处理那么多的Observable。