Как использовать shareReplay для кеширования нескольких запросов? - PullRequest
0 голосов
/ 28 октября 2019

У меня проблемы с оператором 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 находится внутри event.component , и эточто я получаю:

screen1

Он работает без оператора shareReplay (даже если загрузка происходит каждый раз, когда я выбираю день, потому что он каждый раз вызывает службу),но если я использую его, приложение вылетает или показывает только значения с первого дня длякаждый день я выбираю.

Как правильно использовать его в этом контексте для извлечения данных определенного дня и вида спорта только один раз и немедленно возвращать эти данные при последующем запросе? Кроме того,как я могу воспроизвести результаты только за один день (так как завтра запросы будут другими)?

Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...