У меня есть функция, которая проверяет, загружена ли сетка или нет, и если нет, она запускает загрузку.Но в настоящее время это приводит к запуску несколько раз для одного и того же значения Loaded
, поэтому оно будет вызывать соответствующее действие несколько раз.У меня сложилось впечатление, что селекторы магазина по умолчанию испускают только разные (измененные) значения?
Моя функция
private gridLoaded(filters: FilteredListingInput): Observable<boolean> {
return this.settings.states.Loaded.pipe(
tap(loaded => {
this.logService.debug(
`Grid ID=<${
this.settings.id
}> this.settings.states.Loaded state = ${loaded}`
);
// Now we get duplicate firings of this action.
if (!loaded) {
this.logService.debug(
`Grid Id=<${
this.settings.id
}> Dispatching action this.settings.stateActions.Read`
);
this.store.dispatch(
new this.settings.stateActions.Read(filters)
);
}
}),
filter(loaded => loaded),
take(1)
);
}
this.settings.states.Loaded
- это селектор из магазина NgRx.Вывод журнала, который я получаю, выглядит следующим образом:
Grid ID=<grid-reviewItem> this.settings.states.Loaded state = false {ignoreIntercept: true}
Grid Id=<grid-reviewItem> Dispatching action this.settings.stateActions.Read {ignoreIntercept: true}
Grid ID=<grid-reviewItem> this.settings.states.Loaded state = true {ignoreIntercept: true}
Grid ID=<grid-reviewItem> Calling FilterClientSide action. Loaded=true {ignoreIntercept: true}
Grid ID=<grid-reviewItem> this.settings.states.Loaded state = true {ignoreIntercept: true}
Grid ID=<grid-reviewItem> Calling FilterClientSide action. Loaded=true {ignoreIntercept: true}
Grid ID=<grid-reviewItem> this.settings.states.Loaded state = true {ignoreIntercept: true}
Grid ID=<grid-reviewItem> Calling FilterClientSide action. Loaded=true {ignoreIntercept: true}
Как я могу убедиться, что соответствующие действия запускаются только один раз?
Редактировать - обновления
Код селектора:
export const getReviewItemsLoaded = createSelector(
getReviewItemState,
fromReviewItems.getReviewItemsLoaded
);
export const getReviewItemState = createSelector(
fromFeature.getForecastState,
(state: fromFeature.ForecastState) => {
return state.reviewItems;
}
);
export const getReviewItemsLoaded = (state: GridNgrxState<ReviewItemListDto>) =>
state.loaded;
export interface GridNgrxState<TItemListDto> {
allItems: TItemListDto[];
filteredItems: TItemListDto[];
totalCount: number;
filters: FilteredListingInput;
loaded: boolean;
loading: boolean;
selectedItems: TItemListDto[];
}
Как видите, мы просто получаем свойство state.loaded
, это тривиальный селектор.
Редукторы , которые изменяютloading
свойство:
export function loadItemsSuccessReducer(state: any, action: GridAction) {
const data = action.payload;
return {
...state,
loading: false,
loaded: true,
totalCount: data.totalCount ? data.totalCount : data.items.length,
allItems: data.items
};
}
export function loadItemsReducer(state: any, action: GridAction) {
return {
...state,
loading: true,
filters: action.payload
};
}
export function loadItemsFailReducer(state: any, action: GridAction) {
return {
...state,
loading: false,
loaded: false
};
}
Действия
export class LoadReviewItemsAction implements Action {
readonly type = LOAD_REVIEWITEMS;
constructor(public payload?: FilteredListingInput) {}
}
export class LoadReviewItemsFailAction implements Action {
readonly type = LOAD_REVIEWITEMS_FAIL;
constructor(public payload: any) {}
}
export class LoadReviewItemsSuccessAction implements Action {
readonly type = LOAD_REVIEWITEMS_SUCCESS;
constructor(public payload: PagedResultDtoOfReviewItemListDto) {}
Эффекты
export class ReviewItemsEffects {
constructor(
private actions$: Actions,
private reviewItemApi: ReviewItemApi
) {}
@Effect()
loadReviewItems$ = this.actions$
.ofType(reviewItemActions.LOAD_REVIEWITEMS)
.pipe(
switchMap((action: reviewItemActions.LoadReviewItemsAction) => {
return this.getDataFromApi(action.payload);
})
);
/**
* Retrieves and filters data from API
*/
private getDataFromApi(filters: FilteredListingInput) {
return this.reviewItemApi.getReviewItems(filters || {}).pipe(
map(
reviewItems =>
new reviewItemActions.LoadReviewItemsSuccessAction(
reviewItems
)
),
catchError(error =>
of(new reviewItemActions.LoadReviewItemsFailAction(error))
)
);
}
}