我正在研究使用NgRx缓存数据的Angular项目。在Submit按钮事件中,我需要从服务器获取20条记录并显示它。现在,我需要为下一次迭代实现分页(仅适用于Next和Previous)。当我发出下一个请求时,我想将响应追加到缓存(NgRx存储),这样我就不必为“上一个”页面的后端发出请求。简而言之,如果缓存已经包含记录,则我不想向服务器发出请求。我应该在哪里以及如何实现分页逻辑?在组件中还是使用Router Resolver?
我当前的实现方式(无效)是:
constructor(
private store: Store<AppState>,
private activatedRoute: ActivatedRoute,
private router: Router
) {
this.guestAds$ = this.store.select(guestAds);
this.activatedRoute.queryParams.subscribe((params: any) => {
if (Object.keys(params).length) {
this.queryParams = params;
this.getAds();
}
});
}
onSubmit() {
const form = this.searchForm.value;
const queryParams = {
searchTerm: form.searchTerm,
category: form.category,
subCategory: form.subCategory,
limit: 20,
startAt: 0,
prevKeys: ''
};
this.router.navigate(['/'], { queryParams });
}
getAds() {
this.guestAds$
.pipe(
tap(ads => {
if (ads.length) {
ads.forEach(ad => {
if (ad.createdAt === Number(this.queryParams.startAt)) {
console.log('Data alreadyd available');
/* some logic */
} else {
this.store.dispatch(LoadAds({payload: this.queryParams}));
}
});
}
}),
).subscribe(/* I dont know if this is required?! */);
}
我的NgRx效果如下:
loadAds$ = createEffect(() =>
this.actions$.pipe(
ofType(GuestAdsActions.LoadAds),
mergeMap((action) => this.guestAdsService.getAds(action.payload)
.pipe(
map((payload: any) => payload.data),
map((payload: Ad[]) => GuestAdsActions.LoadAdsSuccess({ payload }),
catchError(() => of(GuestAdsActions.LoadAdsSuccess({ payload: []}))
)
)
)
)));
我的服务如下:
getAds(queryParams: QueryParams) {
console.log(queryParams);
return this.http.get(`${this.BASE_URL}/ads`, { params: { ...queryParams } });
}
我正在基于路由器查询参数更改侦听器调用getAds()方法。我究竟做错了什么?如果有人可以帮助我,我将不胜感激。谢谢!
编辑:增加了效果和服务
答案 0 :(得分:0)
嗯,这很复杂,但是我会尝试描述。
- 更改状态,将
GuestAd
从Array
保存到Map
export interface State {
... // other properties
guestAds : Map<string,Array<GuestAd>>;
}
- 更改减速器以处理地图操作:
... // some other reducer cases
case GuestAdsActions.LoadAdsSuccess:
const key = JSON.stringify(action.payload); // since your parameter object is complex better using string equality.
if (state.guestAds.has(key )) { // if exists do not modify
return state;
} else {
const cloneSet = new Map(state.guestAds);
cloneSet.set(key, action.data);
return {...state, guestAds: cloneSet};
}
- 添加另一个接受参数的选择器
export const selectMappedGuestAds = createSelector(guestAds, (mappings, props) => mappings.get(JSON.stringify(props.payload));
- 修改效果以检查数据是否可用:
loadAds$ = createEffect(() =>
this.actions$.pipe(
ofType(GuestAdsActions.LoadAds),
withLatestFrom(this.store.select(guestAds), action,data=>{
const key = JSON.stringify(action.payload); // again we need to stringify
return data.has(key ) && data.get(key).length > 0 ? null : action;
}), // check store if has it? if has cached data return null
fiter(action=> !!action), // if result not null then we need to request it from server
switchMap((action) => this.guestAdsService.getAds(action.payload)
.pipe(
map((payload: any) => payload.data),
map((payload: Ad[]) => GuestAdsActions.LoadAdsSuccess({ payload }),
catchError(() => of(GuestAdsActions.LoadAdsSuccess({ payload: []}))
)
)
)
)));
- 最后将您的商店请求更改为参数一:
this.store.select(selectMappedGuestAds,{payload:queryParams});