簡體   English   中英

Angular 6多次調用subscribe()

[英]Angular 6 call subscribe() for Observable multiple times

我有兩個組件: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);
  }
}

在此先感謝您,任何幫助將不勝感激。

作為實驗,如果您執行以下操作:

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請求的可觀察對象都已完成,因此可以安全地取消訂閱,因為這是在可觀察對象完成時自動完成的。

編輯:

環顧四周后,我發現了這些帖子:
是否需要退訂Http方法創建的可觀察對象?
防止Angular 2中的內存泄漏?

注釋和答案解釋了HttpClient.get()訂閱在其自身清除后HttpClient.get()清除,因此您無需取消訂閱。 這意味着可以多次調用.subscribe()

如果您多次訂閱電話,則在銷毀組件時取消訂閱。

像這樣更改組件:

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);
  });
 }
}

loadItems()調用僅subscribe一次。
實際發生的情況是,您在notificationService.item$的訂閱中多次調用loadItems()
如果您僅出於此目的需要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]);
  }

}

您現在正在做的是:

  1. 制作新商品,發送到服務器
  2. 服務器將成功響應與項目發送到項目服務。 通知通知服務。 您實際上不會對此項目做任何事情,但請對其進行驗證。
  3. 您的通知服務獲取項目,通知您的列表組件。
  4. 您的列表組件檢查項目是否有效,然后向服務器發送另一個請求以獲取更新的列表
  5. 列表組件為更新的列表訂閱列表服務。 到時更新。

簡而言之,對於每個新項目,您都會向服務器發出2個請求,並獲得2個響應。

您可以看到這里有很多冗余。 讓我們嘗試簡化事情:

  1. 制作新商品,發送到服務器
  2. 服務器發送帶有更新的項目列表的成功響應。 僅當收到的商品有效時,才會發送該商品列表,否則將返回錯誤響應
  3. 您的通知服務已訂閱此並獲取服務器已驗證的 項目列表 ,並將此新項目列表發送給您的列表服務。
  4. 列出組件以新數據更新視圖。

現在,您每次只發出一個請求,而不是兩個。 而且您不再需要處理那么多的Observable。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM