我正在使用NGRX缓存一些数据,如下所示:
@Effect() public getProductList$ = this.actions$
.pipe(
ofType<actionType>(actions.ACTION_NAME),
withLatestFrom(this.store.select(x => x.storeSlice), (action: any, store: any) => store.data),
switchMap((data: any) => {
if (data.items.length > 0) {
return [new actions.Success(data.items)];
}
const localData: any[] = localStorage.getItem(...);
if (localData != null) {
return [new actions.SuccessAction(localData)];
}
else {
return this.apiService.getAll()
.pipe(
map(result => new actions.Success(result)),
catchError(error => actions.Failure(error));
}
})
);
基本上,我尝试首先从商店中获取数据,如果结果数组中有项目,我将对数据返回成功操作。否则,我尝试从localStorage
加载数据,如果存在,我将返回成功操作。最后,如果没有缓存的数据,我将调用API来获取数据,这可能会导致成功或失败操作。
问题在于数据增长太多,我无法再将其存储在localStorage
中,所以我需要使用IndexedDb
,它可以实现诺言。
我在IndexedDb api
周围创建了包装服务,并且我的方法返回了带有数据的Observable
。因此,我需要通过服务电话来切换const localData: any[] = localStorage.getItem(...);
。使用localStorage
可以使一切正常,因为它是同步的,但是IndexedDb
却不是。
我尝试了类似的方法,但是它不起作用:
@Effect() public getProductList$ = this.actions$
.pipe(
ofType<actionType>(actions.ACTION_NAME),
withLatestFrom(this.store.select(x => x.storeSlice), (action: any, store: any) => store.data),
switchMap((data: any) => {
if (data.items.length > 0) {
return [new actions.Success(data.items)];
}
return this.idb.getData().map(localData => {
if (localData != null) {
return [new actions.SuccessAction(localData)];
}
else {
return this.apiService.getAll()
.pipe(
map(result => new actions.Success(result)),
catchError(error => actions.Failure(error));
}
});
})
);
这不起作用,因为我返回的是Observable而不是实际的action
。但是,如何从Observable
中提取数据?是否有一个rxjs运算符可以帮助我解决这个问题?
如果将来有人来这里,这就是解决方案:
@Effect() public getProductList$ = this.actions$
.pipe(
ofType<actionType>(actions.ACTION_NAME),
withLatestFrom(this.store.select(x => x.storeSlice), (action: any, store: any) => store.data),
switchMap((data: any) => {
if (data.items.length > 0) {
return [new actions.Success(data.items)];
}
return this.idb.getData()
.pipe(
map(data => new actions.SuccessAction(data),
switchMap(successActionFromIDB => {
if (successActionFromIDB.payload.length > 0) {
return of(successActionFromIDB);
}
else {
return this.apiService.getAll()
.pipe(
tap(data => this.idb.setData(data)),
map(data => new actions.SuccessAction(data)),
catchError(error => new actions.FailureAction(error))
)
}
})
)
);
})
);
答案 0 :(得分:1)
您可以这样做:
@Effect() public getProductList$ = this.actions$
.pipe(
ofType<actionType>(actions.ACTION_NAME),
withLatestFrom(this.store.select(x => x.storeSlice), (action: any, store: any) => store.data),
switchMap((data: any) => {
// Return value as an observable with of()
if (data.items.length > 0) {
return of([new actions.Success(data.items)]);
}
const localData: any[] = localStorage.getItem(...);
if (localData != null) {
// Return value as an observable with of()
return of([new actions.SuccessAction(localData)]);
}
// Return value as an observable with
return this.apiService.getAll()
.pipe(
map(result => [new actions.Success(result) as any]),
catchError(error => [actions.Failure(error) as any])
);
}),
// Flat map the observable result from the switchMap. This will flatten
// your result to an actual value.
flatMap(data => data)
);