Вы должны использовать либо ReplaySubject
, либо BehaviorSubject
. Первое вы будете использовать, если хотите, чтобы оно испускало значение только при получении первого значения. Последнее, если вы хотите, чтобы оно имело значение по умолчанию, например, пустой массив.
Вы можете даже обновить свой сервис, чтобы он был полностью с потоками, что всегда будет поддерживать ваши данные в актуальном состоянии и значительно сокращает использование .subscribe
, которое является большой причиной утечек памяти (незакрытые подписки):
@Injectable({
providedIn: 'root'
})
export class DeviceManagerService {
readonly devicesInfo$ = this.apiService.getDeviceStatus().pipe(
shareReplay(1)
);
readonly devices$ = this.devicesInfo$.pipe(
map((devicesInfo) => devicesInfo.record
.filter((dev, i, arr) => arr.findIndex(({ devid }) => devid === dev.devid) === i)
),
shareReplay(1)
);
constructor(private apiService: ApiService ) {}
}
И поскольку вы используете потоки сейчас, использование MatTableDataSource
становится устаревшим, поскольку вы можете просто передать наблюдаемый в качестве источника данных для таблицы соответствия:
export class DevicesComponent {
displayedColumns: string[] = ['deviceID'];
readonly devices$ = this.deviceManager.devices$;
constructor(private deviceManager: DeviceManagerService) {}
}
Как видите, я не использую BehaviorSubject
или ReplaySubject
, но я использую оператор shareReplay()
. Что в основном превращает наблюдаемое в ReplaySubject
и распределяет подписки среди подписчиков.
Имейте в виду, однако, что использование shareReplay(1)
следует делать с осторожностью. Если у вас есть наблюдаемое, которое не завершается, подписка не заканчивается, даже если компонент уничтожается. Вы можете либо добавить takeUntil(//destroy observable)
, либо изменить его на shareReplay({ refCount: true, bufferSize: 1 })
. Последний перезапустит исходный Observable
, как только количество подписок достигнет 0, и после этого снова будет подписано. Хорошая вещь - то, что вещи действительно убираются. Так что .. это просто сноска :)