更新时间:2021-07-22 08:48:07
正如您所发现的,您不能使用下面的原始解决方案,因为 combineLatest
将在 changePageNumber
时同时触发和 changeFilters
是从 applyFilters
调用的.
As you have discovered, you cannot use the original solution below as combineLatest
will fire both when changePageNumber
and changeFilters
are called from applyFilters
.
另一种方法是使用通过 scan
运算符实现的单个状态对象,并一次更新其中的一个或多个属性.这意味着从它触发的服务只会被每个动作"调用一次.
An alternative approach is to use a single state object implemented via the scan
operator, and update one or more properties in it at a time. This means that the service firing from it will only be called once per 'action'.
顺便说一句,您当前正在每个 BehaviorSubject 中存储您的状态",并将其组合起来.
BTW you are currently storing your 'state' in each BehaviorSubject, and combining it.
class ListState {
searchItem: any = "";
pageLimit: any = 10;
pageNumber: any = 0;
ordering: any = "asc";
filtering: any = "";
}
const listStateUpdatesSubject = new BehaviorSubject<Partial<ListState>>(null);
const listStateUpdates$ = listStateUpdatesSubject.asObservable();
// fires once per state update, which can consist of multiple properties
const currListState$ = listStateUpdates$.pipe(
filter(update => !!update),
scan<Partial<ListState>, ListState>(
(acc, value) => ({ ...acc, ...value }), new ListState)
);
const callListService$ = currListState$.pipe(map(state => listService(state)));
function changeOrdering(listOreder: string) {
changeState({ ordering: listOreder });
}
function changeFilters(filters: any) {
changeState({ pageNumber: 0, filtering: filters }); // set both page number and filtering
}
// etc
这是一个工作演示:https://stackblitz.com/edit/so-rxjs-filtering-2?file=index.ts,请注意对 changeFilters
的调用会导致服务仅被调用一次.
Here is a working demo: https://stackblitz.com/edit/so-rxjs-filtering-2?file=index.ts, note that a call to changeFilters
results in the service being called once only.
原始解决方案
创建一个监听 filteringAction$
的新 observable,执行所需的操作并在 combineLatest
中使用新的 observable.
Create a new observable that listens to filteringAction$
, perform the desired actions and use that new observable within the combineLatest
.
...
orderingAction$ = this.orderingSubject.asObservable();
filteringAction$ = this.filteringSubject.asObservable();
filterApplied$ = filteringAction$.pipe(map(filter => applyFilters(filter)));
applyFilters(filters: any) {
this.listSearchService.changePageNumber(0);
this.listSearchService.changeFilters(filters);
return filters;
}
combination$ = Observable.combineLatest(
this.searchItemAction$,
this.pageLimitAction$,
this.pageNumberAction$,
this.orderingAction$,
this.filterApplied$ // instead of filteringAction$
)