How to build a service that gets values async but also perfoms tasks on that data, like filtering?

白昼怎懂夜的黑 提交于 2019-12-13 03:54:19

问题


I have a service "provided in root" that:

  • gets data once from an API
  • should handle a mapping on that data
  • should provide that data to other components if needed

This data doesn't need to be reloaded throughout the lifecycle of the app. It's only reloaded when the user refreshes the browser. All of the data is going to be used at some point - so it makes no sense to make http requests on each getOneById(). A filter is faster in this case.

The mockup of the service looks something like this:

export class MyTypeService {
  items: MyType[] = [];
  items$ = new BehaviorSubject<MyType[]>(this.items);

  constructor(private http: HttpClient) { }

  getData(): Subscription {
    return this.http.get<SearchResult>(
      'path'
    ).pipe(
      map((response: any) => {
        this.items = response;
        return this.items;
      }),
      catchError(error => {
        // removed from the question for simplicty
        this.handleError(error);
        return of([]);
      })
    ).subscribe(result => this.items$.next(result));
  }

  getOneById(id: string): MyType|null {
    for (let item of this.items) {
      if (item.id === id) {
        return item;
      }
    }

    return null;
  }
}

Now I'm lost with these questions:

  • Should the service itself subscribe to items$?
    Or should all member functions, like getOneById() subscribe?
    (Which could mean, that I can remove items.
  • Should I call getData() in the constructor, as I definitely need the values during the run of the app?
    Or should it be called the first time the values are actually needed?
  • How can I tell a component, that it's safe to use getOneById()?

回答1:


You shouldn't have items without Observable at all. Something like this should work so you don't make http request when you dont need it

  itemsSub: BehaviorSubject<any[]> = new BehaviorSubject(null);

  getItems(): Observable<any[]> {
    return this.itemsSub.pipe(mergeMap(items => {
      if (items) {
        return of(items); // Return items if you already have them
      } else {
        // If you don't have them, get them and emit on subject
        return this.http.get().pipe(tap((items) => this.itemsSub.next(items))); 
      }
    }))
  }

  getItemsFiltered() {
    return this.getItems().pipe(filter(items => !!items));
  }


来源:https://stackoverflow.com/questions/56818773/how-to-build-a-service-that-gets-values-async-but-also-perfoms-tasks-on-that-dat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!