web-dev-qa-db-ja.com

Angular2、ngOnDestroyのイベントからサブスクライブ解除

私のアプリケーションには、EventServiceを使用して通信するコンポーネントがいくつかあります。

@Injectable()
export class EventService {
  public myEvent: EventEmitter<any> = new EventEmitter();
  constructor() {}
}

このサービスは、ボタンがクリックされたときにイベントを発行するEmitterComponentに注入されます

@Component({
  selector: 'emitter',
  template: `<button (click)="onClick()">Click me</button>`,
})
export class EmitterComponent {
  constructor(private eventService:EventService) {}
  onClick() {
    this.eventService.myEvent.emit();
  }
}

そして、イベントにサブスクライブするReceiverComponentで、受信したイベントごとにカウンターをインクリメントします

@Component({
  selector: 'receiver',
  template: `Count: {{count}}`,
})
export class ReceiverComponent {
  public count = 0;
  constructor(private eventService:EventService) {
    this.eventService.myEvent.subscribe(() => this.count++;);
  }
}

アプリケーションには複数のビューがあります(この例では2つだけです):PageAPageBEmitterComponentReceiverComponentPageAにあります。 PageBに移動してPageAに戻るたびに、新しいReceiverComponentが作成され、EmitterComponentのボタンをクリックすると、イベントコールバック関数of ReceiverComponentが数回実行されます。

これを避けるため、ReceiverComponentmyEventからngOnDestroyの購読を解除します

ngOnDestroy() {
  this.eventService.myEvent.unsubscribe();
}

しかし、これにより次の例外が発生します

EXCEPTION: Error during instantiation of ReceiverComponent!.
ORIGINAL EXCEPTION: Error: Cannot subscribe to a disposed Subject

どうすればそれを回避できますか?正しく退会する方法は?

理解を深めるために、これを作成しました plunker コンソールでエラーとコメントを確認できます。

23
TizianoL

.subscribe()からサブスクリプションを取得します。 unsubscribe()メソッドを使用して、サブスクリプションをキャンセルします。

@Component({
  selector: 'receiver',
  template: `Count: {{count}}`,
})
export class ReceiverComponent {
  public count = 0;
  private subscription;
  constructor(private eventService:EventService) {
    this.subscription = this.eventService.myEvent.subscribe(() => this.count++;);
  }
  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

こちらもご覧ください

33

以下に説明するように、サブスクリプションをキャンセルする必要があると思います。

export class ReceiverComponent {
  public count = 0;
  private id;

  constructor(private eventService:EventService) {
    this.id = Date.now();
    console.log("ReceiverComponent constructor " + this.id);
    this.subscription = this.eventService.myEvent.subscribe(() => {
      console.log("count " + this.count + " (id ReceiverComponent instance: " + this.id + ")");
      this.count++;
    });
  }

  ngOnDestroy() {
    console.log("onDestroy of ReceiverComponent " + this.id)
    //this cause "Cannot subscribe to a disposed Subject."
    //this.eventService.myEvent.unsubscribe();
    this.subscription.unsubscribe();
  }
}

実際、EventEmittersは共有オブザーバブル、つまりホットオブザーバブルです。興味のあるリンクは次のとおりです。 https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md

お役に立てばと思います、ティエリー

2