Есть ли способ автоматически проверить, находится ли объект в хранилище, используя данные NgRx?

#ngrx #ngrx-data

Вопрос:

Чтобы уменьшить сетевой трафик, мне нужно проверить, находится ли объект с заданным идентификатором в магазине, а если нет, его следует запросить с сервера. Я не смог найти никакой конфигурации для этого, поэтому я просто жестко закодировал логику, используя RxJS, как показано ниже.

Есть ли способ настроить это с помощью данных NgRx/NgRx? Есть ли способ настроить, как долго объект может находиться в хранилище без необходимости повторного запроса?

 import {
  EntityCollectionServiceBase,
  EntityCollectionServiceElementsFactory,
} from '@ngrx/data';
import { Injectable } from '@angular/core';

import { MyEntity } from 'app/state/my-entity/MyEntity';
import { Observable, of, Subject } from 'rxjs';
import { distinct, filter, switchMap, tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})
export class MyEntityDataService extends EntityCollectionServiceBase<MyEntity> {

  private id$ = new Subject<string|number>();

  constructor(serviceElementsFactory: EntityCollectionServiceElementsFactory) {
    super('MyEntity', serviceElementsFactory);

    // Fetching the data if not yet there
    this.id$.pipe(
      // Preventing multiple requests e.g. when multiple components
      // are requesting the same data
      distinct(),
      switchMap(
        (id: string|number): Observable<MyEntity | undefined> => this.filteredEntities$.pipe(
          switchMap(
            (entityCollection: MyEntity[]): Observable<MyEntity | undefined> => {

              const thatEntity: MyEntity | undefined =
                entityCollection.find((entity: MyEntity) => `${entity.id}` === `${id}`);

              return of(thatEntity).pipe(
                filter((v: MyEntity | undefined): boolean => !v),
                tap(() => super.getByKey(id))
              )
            }
          ),
        ),
      ),
    ).subscribe();
  }

  getByKey(id: string|number): Observable<MyEntity> {

    this.id$.next(id);

    return this.filteredEntities$.pipe(
      switchMap(
        (entityCollection: MyEntity[]) : Observable<MyEntity> => {
          const thatEntity: MyEntity | undefined = entityCollection.find(
            (entity: MyEntity) => `${entity.id}` === `${id}`
          );
          return thatEntity ? of(thatEntity) : of();
        }
      ),
    );
  }
}
 

Ответ №1:

Я столкнулся с той же проблемой, и лучшим решением для меня было проверить ее на эффект, прежде чем отправлять действие.

 //selectIdExists:selector recieve ID and return true if loaded or false if not found
//user should dispatch initialFindById and the effect will decide either to dispatch findById or no dispatching

initialFindById$ = createEffect(() => this.actions$.pipe(
        ofType(actions.initialFindById),
        mergeMap(action => this.store.select(selectors.selectIdExists(action.id))
            .pipe(
                filter(found => found == false),//Id not found 
                map(() => actions.findById({ id: action.id })),
            ))
    ));
 

если вы хотите убедиться, что извлекаете данные, даже если в хранилище есть данные, просто отправьте findbyId действие вместо этого