NgRx 和 RxJS:依赖状态选择器
NgRx and RxJS : Dependent State Selector
我有一个组件在构造函数中订阅了多个状态片段。
@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)。 PGrid
组件中的 LoadData()
方法依赖于第一个订阅的 this.Data。
当我 运行 代码时,我得到了未定义的代码。数据虽然 selectedProcess.Data
有价值
this.store.pipe(
select(fromReports.getProcessState),
takeWhile(() => this.componentActive))
.subscribe(selectedProcess=> {
if (selectedProcess) {
this.Data= selectedProcess.Data; //undefined
}
});
这意味着当订阅状态的第二个切片并调用 LoadData()
方法时,它会出错,因为 this.Data
未定义。
我相信这是由于 Observable 的工作方式所致,并且由于它们是异步的,所以一个函数可能不会 return 另一个函数之前的值。
问题:1 为什么 this.Data= selectedProcess.Data;
将 this.Data
设置为未定义,即使 selectedProcess.Data
具有值
问题 2:我看过 flatMap
和 switchMap
,但由于我是 RxJS 和 NgRx 的新手,所以我对如何利用它们感到困惑。有什么建议吗?
P.S 同样,我在我的 ngOnInit()
中分别订阅了 2 个切片,这是首选方式还是我应该合并它们?
万物皆流。
每个可观察流都应以 $.
命名
避免在最后使用订阅。
combineLatest 在每个 Observable 至少发出一个值之前不会发出初始值。
tap 可用于副作用和日志记录,不影响流。这是 "I don't know what I'm doing operator"。我大方地使用它。
伪代码
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
我有一个组件在构造函数中订阅了多个状态片段。
@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)。 PGrid
组件中的 LoadData()
方法依赖于第一个订阅的 this.Data。
当我 运行 代码时,我得到了未定义的代码。数据虽然 selectedProcess.Data
有价值
this.store.pipe(
select(fromReports.getProcessState),
takeWhile(() => this.componentActive))
.subscribe(selectedProcess=> {
if (selectedProcess) {
this.Data= selectedProcess.Data; //undefined
}
});
这意味着当订阅状态的第二个切片并调用 LoadData()
方法时,它会出错,因为 this.Data
未定义。
我相信这是由于 Observable 的工作方式所致,并且由于它们是异步的,所以一个函数可能不会 return 另一个函数之前的值。
问题:1 为什么 this.Data= selectedProcess.Data;
将 this.Data
设置为未定义,即使 selectedProcess.Data
具有值
问题 2:我看过 flatMap
和 switchMap
,但由于我是 RxJS 和 NgRx 的新手,所以我对如何利用它们感到困惑。有什么建议吗?
P.S 同样,我在我的 ngOnInit()
中分别订阅了 2 个切片,这是首选方式还是我应该合并它们?
万物皆流。
每个可观察流都应以 $.
命名避免在最后使用订阅。
combineLatest 在每个 Observable 至少发出一个值之前不会发出初始值。
tap 可用于副作用和日志记录,不影响流。这是 "I don't know what I'm doing operator"。我大方地使用它。
伪代码
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}`)
);