簡體   English   中英

Angular / RxJs - 在組件取消訂閱()后在服務中調用next()導致ObjectUnsubscribedError

[英]Angular/RxJs - Calling next() on Observable in service after component was unsubscribe() cause ObjectUnsubscribedError

我有一個定義公共Subject<\/code>的 Angular 服務。 稍后在某些情況下,服務將在此主題上調用.next()<\/code> 。

此外,我有一個 Angular 組件,它在它的 ngOnInit() 方法中.subscribe()<\/code>到這個 Subject,並在它的ngOnInit()<\/code>方法中調用.unsubscribe()<\/code> ngOnDestroy()<\/code>

雖然服務和組件都還活着,但我的代碼工作正常。 但是,用戶可以在我的應用程序中單擊不同的選項卡。 這導致我的組件卸載並調用其ngOnDestroy()<\/code>方法,這意味着 Observable 已取消訂閱。

從這一點開始,組件不再存在,但服務仍然存在 - 其他組件仍在使用它。 當服務在組件調用.unsubscribe()<\/code>之后調用.next()<\/code>方法時,會拋出此錯誤ObjectUnsubscribedError<\/em> 。 ERROR Error: Uncaught (in promise): ObjectUnsubscribedError: object unsubscribed<\/code>

此外,稍后如果用戶返回到包含該組件的選項卡,則會執行ngOnInit()<\/code>並且重新訂閱此 observable 會再次引發相同的錯誤。

我做錯了什么,我該如何解決這些錯誤?

import { Subject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class StatusService {
  public statusChange$: Subject<number>;

  public constructor(...) {
    this.statusChange$ = new Subject<number>();
  }

  public someInternalLogic(someNumber: number): void {
    this.statusChange$.next(someNumber);
    // this will throw an error if StatusComponent call .unsubscribe()
  }
}

@Component({
  selector: 'app-status',
  templateUrl: './status.component.html',
  styleUrls: ['./status.component.scss']
})
export class StatusComponent implements OnInit, OnDestroy {
  public constructor(
    private _statusService: StatusService) {}

    public ngOnInit(): void {
      this._statusService.statusChange$.subscribe(value => this._onStatusChange(value));
  }

  public ngOnDestroy(): void {
    this._statusService.statusChange$.unsubscribe();
    // after this point if the StatusService calling .next() an error will be thrown
  }

  private _onStatusChange(value: number): void {
    // ....
  }
}

您不需要在組件中取消訂閱服務主題。 而是在組件中為服務主題創建訂閱變量,並在組件銷毀時取消訂閱

subscription!: Subscription;

public ngOnInit(): void {
    this.subscription = this._statusService.statusChange$.subscribe(value => this._onStatusChange(value));
}

public ngOnDestroy(): void {
    this.subscription.unsubscribe();
}

private _onStatusChange(value: number): void {
    // ....
}

另一種集體取消訂閱 OnDestroy 事件的方法是使用 takeUntil 運算符。 因此,您不必存儲每個訂閱,而是可以創建一個主題並在組件被銷毀時觸發它。

想象一下,您的服務有多個主題,並且您的組件訂閱了每個主題。 在這種情況下,您必須通過類屬性(或一系列訂閱)存儲您的所有訂閱,並且您必須手動取消訂閱每個訂閱。

class myComponent {

  // create any subject which allows you to push into
  // when your component gets destroyed
  private onDestroy = new Subject<void>();

  public ngOnInit(): void {
    // Subscription #1
    this._statusService.statusChange_1$.pipe(
      tap(() => /* do something */),
      // takeUntil will listen to changes of the onDestroy subject
      // and whenever you trigger it by this.onDestroy.next() it will
      // automatically unsubsribe for you
      takeUntil(this.onDestroy)
    ).subscribe();

    // Subscription #2
    this._statusService.statusChange_2$.pipe(
      takeUntil(this.onDestroy)
    ).subscribe(value => {
      /* do something else */
      // you can put your logic into your subscribe method as well
      // like you did in your question
    });

    // Any number of more subscriptions...
    // ...
  }

  public ngOndestroy(): void {
    // Notify the observers to unsibscribe
    this.onDestroy.next();
  }
}

暫無
暫無

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

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