If you are using Akita for state management, this article might be helpful to you.
// BaseEntityService.ts
import { Observable } from 'rxjs';
import { BaseQuery } from './BaseQuery';
import { EntityStore, EntityState } from '@datorama/akita';
import { tap, delay } from 'rxjs/operators';
export abstract class BaseEntityService<TParams, TView, TResult> {
constructor(
protected query: BaseQuery<TView, TParams>,
protected entityStore: EntityStore<EntityState<TView>, TView>
) {
}
protected abstract getFromApi(params: TParams): Observable<TResult>;
protected abstract getFromStore(params: TParams): Observable<TResult>;
protected selectFromStore(params: TParams): Observable<TView> {
return this.query.selectData(params).pipe(
delay(1), // if removed, ui will not update with current data
)
}
get(params: TParams): Observable<TResult> {
return this.toggleLoading(
() => {
if (!this.query.hasData(params))
return this.getFromApi(params);
else
return this.getFromStore(params);
}
);
}
private toggleLoading<TResult>(o: () => Observable<TResult>) {
this.entityStore.setLoading(true);
return o().pipe(
tap((x) => {
this.entityStore.setLoading(false);
})
)
}
}
BaseEntityService
handles abstraction for getting data from api or store. It also implements custom setting of entity loading property via toggleLoading
.
// BaseQuery.ts
import { EntityState, QueryEntity } from "@datorama/akita";
import { filter } from 'rxjs/operators';
export abstract class BaseQuery<TView, TParams> extends QueryEntity<EntityState<TView>, TView> {
selectData(params: TParams) {
const key = JSON.stringify(params);
return this.selectEntity(key).pipe(
filter(x => !!x)
)
}
selectDataNullable(params: TParams) {
const key = JSON.stringify(params);
return this.selectEntity(key);
}
hasData(params: TParams) {
const key = JSON.stringify(params);
return this.hasEntity(key);
}
}
BaseQuery
contains custom selection of existing store data. In our app, we use stringified parameters as keys.
Top comments (0)