1

I have a component that subscribes to multiple slices of state in the constructor.

 @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);
              }
          });
}

The first subscription subscribes to an array of objects while the second subscription calls a method in another component (@ViewChild(PComponent) PGrid). The LoadData() method in PGrid component depends upon this.Data from the first subscription.

When I run the code I get undefined for this. Data although there selectedProcess.Data has value

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

  }
          });

This means when the second slice of the state is subscribed and LoadData() method is called it errors out as this.Data is undefined.

I believe this is due to how Observable work and since they are async one function may not return the value before the other.

Que: 1 Why this.Data= selectedProcess.Data; sets this.Data to undefined even though selectedProcess.Data has value

Que 2: I have looked at flatMap and switchMap but since I am new to RxJS and NgRx I am confused about how to leverage them. Any tips?

P.S On a similar note, I am subscribing to 2 slices separately in my ngOnInit(), is this a preferred way or should I combine them?

Hamed
  • 5,867
  • 4
  • 32
  • 56
Abhi.Net
  • 722
  • 3
  • 11
  • 37

1 Answers1

1

Everything is a stream.

Every observable stream should be named with a $.

Avoid using subscribe until the end.

combineLatest will not emit an initial value until each observable emits at least one value.

tap can be used for side effects and logging and does not affect the stream. It's the "I don't know what I'm doing operator". I use it liberally.

Pseudo code

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

Andrew Allen
  • 6,512
  • 5
  • 30
  • 73
  • Thanks, nicely explained. I did end up using combine latest but the way you explained in your example cleared it up for me. – Abhi.Net Feb 12 '20 at 23:08
  • @Abhi.Net did or did not? Thinking a bit more carefully I think [skipUntil](https://www.learnrxjs.io/learn-rxjs/operators/filtering/skipuntil) is better suited anyway – Andrew Allen Feb 12 '20 at 23:25
  • It did but I'll try skipUntil too. I have marked yours as an answer because it actually helped me understand the problem. RxJS and Observable can be tricky because you have to change your way of thinking.. – Abhi.Net Feb 13 '20 at 02:23