RxJS BehaviorSubject запрос на обналичивание от http call - PullRequest
0 голосов
/ 01 апреля 2019

Мне трудно найти решение для кэширования http-запроса в BehaviorSubject.Я хотел иметь только один метод обналичивания и получения стоимости.Пример ниже:

@Injectable({
  providedIn: 'root'
})
export class DataStoreService {

  private readonly initialState: DataState = {
    data: string,
    loaded: false
  };

  private data$: BehaviorSubject<DataState> = new BehaviorSubject<DataState>(this.initialState);

  constructor(private dataService: DataService) { }

  getData$(id: string): Observable<string> {
    return this.data$.asObservable()
      .pipe(
        switchMap((state: DataState) => {
          if (!state.loaded) {
            this.dataService.getData$(id);
          } else {
            return of(state.data);
          }
        }),
        withLatestFrom(this.data$.asObservable()),
        map(([data, state]) => {
          if (!state.loaded) {
            this.data$.next({
              loaded: true,
              data
            });
          }
          return data;
        })
      );
  }
}

Я еще не тестировал его (сервис не работает), но пока выглядит нормально.Кто-нибудь знает какое-нибудь лучшее решение, чтобы в rxjs было меньше трубопроводов и условных выражений (если / еще) в rxjs для такого вида использования?

Ответы [ 3 ]

1 голос
/ 01 апреля 2019

Я смотрю на это немного по-другому и на самом деле не использую тему поведения, просто переменную.Если это вариант для вас, вы можете рассмотреть:

data;

getData$(id: string): Observable<string> {
  if (data) {
    return of(data)
  } else {
    return this.dataService.getData$(id).pipe(
      tap(dat => this.data = dat)
    )
  }
}
1 голос
/ 04 апреля 2019

Вместо BehaviorSubject вы можете использовать оператор shareReplay, который внутренне использует ReplaySubject и воспроизводит n последних значений для будущих подписчиков.

private data$: Observable<string>;

getData$(id: string): Observable<string> {
  if (!this.data$) {
    this.data$ = this.dataService.getData$(id).pipe(shareReplay(1));
  } 
  return this.data$;
}

Первая подписка на getData$ позвонит this.dataService.getData$.Все последующие подписки получат данные этого первого звонка, воспроизведенные на data$.

1 голос
/ 01 апреля 2019

Объекты BehaviourSubjects имеют очень простой метод доступа к значениям в ".value".

Так что ваш код может выглядеть примерно так:

getData$(id: String): Observable<string> {
  const dataValue = this.data$.value;
  if (dataValue.loaded === true) {
    return of(dataValue.data);
  } else {
    return this.dataService.getData$(id).pipe( map( (result: string) => { this.data$.next({ loaded: true, data: result}; return of(result); );
  }
}

Надеюсь, это поможет.

...