NgRx и Rx JS: зависимый селектор состояний - PullRequest
1 голос
/ 12 февраля 2020

У меня есть компонент, который подписывается на несколько частей состояния в конструкторе.

 @ViewChild(PComponent) PGrid: PComponent;

ngOnInit() {
    this.store.pipe(
          select(fromReports.getProcessState),
          takeWhile(() => this.componentActive))
          .subscribe(selectedProcess=> {
            if (selectedProcess) {
              this.Data= selectedProcess.Data;
  }
          });

  this.store.pipe(
          select(fromReports.getProcessAnalysis),
          takeWhile(() => this.componentActive))
          .subscribe(analysisData => {
            if (analysisData) {
              this.PGrid.LoadData(analysisData);
              }
          });
}

Первая подписка подписывается на массив объектов, тогда как вторая подписка вызывает метод в другом компоненте (@ViewChild (PComponent) PGrid). Метод LoadData() в компоненте PGrid зависит от этого. Данные первой подписки.

Когда я запускаю код, я получаю неопределенный для этого. Данные, хотя selectedProcess.Data, имеют значение

this.store.pipe(
          select(fromReports.getProcessState),
          takeWhile(() => this.componentActive))
          .subscribe(selectedProcess=> {
            if (selectedProcess) {
              this.Data= selectedProcess.Data; //undefined

  }
          });

Это означает, что когда подписывается второй фрагмент состояния и метод LoadData() вызывает его ошибки, поскольку this.Data не определено.

Я полагаю, это связано с тем, как работают Observable и поскольку они асинхронные c одна функция может не возвращать значение раньше другой.

Que: 1 Почему this.Data= selectedProcess.Data; устанавливает this.Data до неопределенного, хотя selectedProcess.Data имеет значение

Que 2: я смотрел на flatMap и switchMap, но так как я новичок в Rx JS и NgRx, я запутался в том, как использовать их , Любые советы?

PS На аналогичной заметке я подписываюсь на 2 среза отдельно в моем ngOnInit(), это предпочтительный способ или я должен их объединить?

1 Ответ

1 голос
/ 12 февраля 2020

Все является потоком.

Каждому наблюдаемому потоку должно быть присвоено имя $.

Избегайте использования подписки до конца.

ОбъединитьПоследние не будет выдавать начальное значение, пока каждое наблюдаемое не выдаст хотя бы одно значение.

tap может использоваться для побочных эффектов и регистрации и не влияет на поток. Это «Я не знаю, что я делаю, оператор» . Я использую это свободно.

Псевдокод

import { of, combineLatest } from "rxjs";
import { map, delay, tap, switchMap } from "rxjs/operators";

const DATA = "selectedProcessData";
const PROCESS_ANALYSIS = "analysis";

const service = {
  getData: () => {
    return of(DATA).pipe(delay(2000));
  },
  loadData: data => {
    return of(data).pipe(delay(2000));
  }
};
const store = {
  getProcessAnalysis: () => {
    return of(PROCESS_ANALYSIS).pipe(delay(2000));
  }
};

let getSelectedProcessData = null;
const getSelectedProcessData$ = service.getData().pipe(
  tap(data => console.log(`getSelectedProcessData::${data}`)),
  tap(data => (getSelectedProcessData = data))
); // mimick getting data from a service

const getAnalysisData$ = store.getProcessAnalysis(); // mimick selection of state

const loadAnalysisData$ = combineLatest(
  getSelectedProcessData$,
  getAnalysisData$
).pipe(
  tap(([getSelectedProcessData, getAnalysisData]) =>
    console.log(`combineLatest::${getSelectedProcessData}, ${getAnalysisData}`)
  ),
  map(([getSelectedProcessData, getAnalysisData]) => getAnalysisData),
  switchMap(getAnalysisData => service.loadData(getAnalysisData))
);

loadAnalysisData$.subscribe(loadedAnalysisData =>
  console.log(`loadedAnalysisData::${loadedAnalysisData}`)
);

Stackblitz

...