Подписка на сервис наблюдаемых выбросов даже после уничтожения компонента - PullRequest
0 голосов
/ 25 февраля 2019

У меня проблемы с наблюдаемым в моем сервисе.Следующий код иллюстрирует это:

@Injectable({
  providedIn: 'root'
})
export class MyService {
  public globalVariable: BehaviorSubject<string> = new BehaviorSubject('');
}

У меня есть компонент компонента:

export class ComponentA implements OnInit {
   constructor(public myService : MyService ) {
      this.myService.globalVariable.next('newValue');
   }

   ngOnInit() {
      this.myService.globalVariable.subscribe(_ => console.log('=> hello'));
   }
}

Модуль приложения:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ComponentAModule,
    ComponentBModule,
    AppRoutingModule
  ],
  providers: [MyService],
  bootstrap: [AppComponent]
})
export class AppModule {
}

И, наконец, структура проекта:

app-module.ts
app-routing.module.ts
-components
-- componentA
--- componentA.module.ts
--- componentA-routing.module.ts
--- componentA.component.ts
--- componentA.component.html
-- componentB
--- componentB.module.ts
--- componentB-routing.module.ts
--- componentB.component.ts
--- componentB.component.html

Теперь проблема, с которой я сталкиваюсь, заключается в том, что когда я перехожу к componentA, вывод будет:

=> hello
=> hello

До тех пор, пока все нормально и ведет себя как я ожидал.Первая подписка запускается, а затем изменяется globalVariable с помощью конструктора componentA.

Однако, когда я перехожу на componentB и возвращаюсь назад к componentA, вывод будет:

=> hello
=> hello
=> hello

Добавляется один раз, когда я возвращаюсь к componentA.Как будто он создает новый экземпляр MyService?Или не уничтожить подписку при выходе?

Информация: Там нет ленивой загрузки.

Ответы [ 3 ]

0 голосов
/ 25 февраля 2019

Подписка должна быть уничтожена вручную, если она не обработана самим Angular.Это в основном относится ко всем имеющимся у вас подпискам httpClient.Например, если вы используете канал | async, Angular позаботится об отмене подписки.

Вызовите yourSubscription.unsubscribe() в ngOnDestroy() вашего компонента.

Что я обычно делаю, это создаю BaseComponent, который делает отписку для меня.Используйте приведенный ниже класс во всех ваших компонентах, расширяя его.Оберните каждый вызов по подписке в super.addSubscription()

import { OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';

/**
 * This class handles the subscribing and unsubscribing of subscriptions to avoid memory leaks
 * and can be inherited by members
 *
 * @export
 */
export abstract class BaseComponent implements OnDestroy {

private subscriptions: Subscription[] = new Array<Subscription>();

ngOnDestroy() {
    this.removeSubscriptions();
}

/**
 * Adds a subscriptions so it can be deleted in ngOnDestroy
 *
 * @param subscription The subscription that should be added
 * @memberof BaseComponent
 */
protected addSubscription(subscription: Subscription) {
    this.subscriptions.push(subscription);
}

/**
 * Unsubscribes from any open subscriptions in the subscriptions array in ngOnDestroy
 *
 * @memberof AbstractBaseComponent
 */
private removeSubscriptions() {
    for (let subscription of this.subscriptions) {
        subscription.unsubscribe();
    }
}
}

ОБНОВЛЕНИЕ

Выполните следующие действия для ngOnInit(), предполагая, что вы используете базовый класс, представленный выше.:

export class ComponentA extends BaseComponent implements OnInit {
    constructor(public myService : MyService ) {
       this.myService.globalVariable.next('newValue');
    }
    ngOnInit() {
       super.addSubscription(
           this.myService.globalVariable.subscribe(_ => console.log('=> hello'))
       )
    }
}
0 голосов
/ 25 февраля 2019

Если вы хотите использовать подписку, а не асинхронный канал, вы можете использовать оператор RxJs takeWhile.Пожалуйста, смотрите код ниже ...

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs';
import { takeWhile, map } from 'rxjs/operators';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit, OnDestroy {
  name = 'Angular';
  isActive: boolean;
  // returned from service.  Does not need to initialized here
  thingToSubscribeTo:Observable<any> = new Observable<any>();

  ngOnInit() {
    this.isActive = true;
    // you can replace with call to service then pipe it.
    this.thingToSubscribeTo.pipe(
      map(res => {
        // handle subscription
      }),
      takeWhile(() => this.isActive)
    );

  }

  ngOnDestroy() {
    this.isActive = false;
  }
}
0 голосов
/ 25 февраля 2019

Вам нужно unsubscribe внутри ngOnDestroy:

import { Subscription } from 'rxjs';

globalVariable$: Subscription;

ngOnInit() {
  this.globalVariable$ = this.myService.globalVariable.subscribe(_ => console.log('=> hello'));
}

ngOnDestroy() {
  this.globalVariable$.unsubscribe();
}
...