如何使用shareReplay缓存多个请求?

时间:2019-10-28 13:37:49

标签: javascript angular typescript ionic-framework

我在与shareReplay运算符配合使用时遇到问题,因为可能我还不了解它的真正工作原理。

我正在构建一个运动应用程序,该应用程序将显示从今天开始的未来6天中的每个运动项目。该API(我无法更改)显示了为一项运动安排的每个事件,因此我必须构建一个过滤器以仅显示与特定日期相关的事件。

这是根据传入日期从API获取事件的服务。 为了举例说明,我仅显示两个运动类别:

event-service.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, from } from 'rxjs';
import { DateService } from './date-service.service'
import { map, shareReplay } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})

export class EventService {

  private NBA_CODE = Constants.SPORT_CODE('NBA');
  private SOCCER_CODE = Constants.SPORT_CODE('SOCCER');

  private nbaObservable$ : Observable<any>;
  private soccerObservable$ : Observable<any>;

  req_day: any;

  constructor(
    private httpClient : HttpClient,
    private dateService: DateService
  ) { }

  getEvents(sport: string, day: string) : Observable<any> {

    let url = //api url
    this.req_day = this.dateService.getDates(day); 
    //getting Moment's requested day object from service
    let offset = moment().utcOffset(); //calculating local offset

    switch (sport) {
      case 'NBA':
        if(!this.nbaObservable$) {
          this.nbaObservable$ = this.httpClient.get<any>(url)
          .pipe(
            map((data) => {
              let data_filtered = this.filter(data);
              return data_filtered
            }),
            shareReplay(1)
          );
        }
        return this.nbaObservable$;
        break;
      case 'SOCCER':
        if(!this.soccerObservable$) {
          this.soccerObservable$ = this.httpClient.get<any>(url)
          .pipe(
            map((data) => {
              let data_filtered = this.filter(data);
              return data_filtered
            }),
            shareReplay(1)
          );
        }
        return this.soccerObservable$;
        break;
    }
 }

 filter(data) {
  if(!(data.events) || data.events.length == undefined || data.events.length == 0) {
        return []; //data is empty or undefined
      } else {
        for (let i=0; i<data.events.length; i++) {
          // start time UTC = moment.utc(data.events[i].startTime)
          let startTime = moment.utc(data.events[i].startTime)._d
          // if req_day is not the same of event day, remove it
          if(!(this.req_day.isSame(startTime, 'day'))) {
            data['events'].splice(i,1);
            i--;
          } else {
              data['events'][i]['startTimeLocale'] = moment.utc(data.events[i].startTime)._d;
            }
          }
        }
        return data;
     }
  }

这是显示数据的 component-details.ts

import { Component, OnInit } from '@angular/core';
import { EventService } from '../../services/event-service.service';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-odds-details',
  templateUrl: './odds-details.component.html',
  styleUrls: ['./odds-details.component.scss'],
})
export class OddsDetails implements OnInit, OnDestroy {

  sub: any;
  categories: any;

  constructor(
    private eventService: EventService,
    private route: ActivatedRoute,
  ) { }

  ngOnInit() {
    this.setCategories();
    this.getOdds();
  }

setCategories() {
  this.categories = [
    {
      apiCall: 'NBA',
      //other data related to apiCall (icon url, events data...)
    },
    {
      apiCall: 'SOCCER',
     //...
    }
  ]
}

  getEvents() {
    this.sub = this.route
    .data
    .subscribe(
      (data) => {
        var day = data.day;
        for (let i=0; i<this.categories.length; i++) {
          this.eventService.getEvents(this.categories[i]['apiCall'], day)
          .subscribe((data) => {
              if(data.events && data.events.length >= 1) {
                this.categories[i]['events'] = data.events;
              } else {
                this.categories[i]['events'] = [];
              }
            })

        }
      })
  }

}

最后,这是 component.html 模板:

<ion-content scrollable>

  <ion-grid>
    <div *ngFor="let p of categories">
      <ion-row *ngIf="p?.events">
          <ion-col size="12">
            <ion-item (click) = "p.open = !p.open">
              <ion-icon [src]="p.url" color="dark">
                </ion-icon>
              <ion-label>
                {{p.title}}
              </ion-label>
              <ion-icon name="arrow-dropright" *ngIf="!p.open"></ion-icon>
              <ion-icon name="arrow-dropdown* ngIf="p.open"></ion-icon>
            </ion-item>
          </ion-col>
          <ion-row *ngFor="let event of p?.events">
            <div *ngIf="p.open">
              <ion-col size="12">
                <div>
                  {{event?.description}}
                </div>
              </ion-col>
              <ion-col size="12">
                <div>
                  {{event?.startTimeLocale}}
                </div>
              </ion-col>
            </div>
          </ion-row>
      </ion-row>
    </div>
  </ion-grid>

</ion-content>

我认为最好只使用一个组件进行日期导航,而使用另一个组件显示每天的事件详细信息,所以 event-details.component 位于事件内部。组件,这就是我得到的:

screen1

它在没有shareReplay运算符的情况下也可以工作(即使每次选择一天都需要花费一些时间来加载,因为它每次都会调用该服务),但是如果我使用它,则该应用程序将崩溃或仅显示第一时间的值我每天选择的一天。

在这种情况下使用它来提取特定日期的数据并且仅运动一次并在以后要求时立即返回这些数据的正确方法是什么? 另外,我怎么只能在一天内重播结果 (因为明天的请求会有所不同)?

谢谢

0 个答案:

没有答案