Как объединить сущности ngrx, используя эффекты (которые периодически возвращаются в результате вызова из внешнего интерфейса)? - PullRequest
1 голос
/ 24 апреля 2020

[angular] [javascript] [ngrx / entity] [ngrx / эффекты] [rxjs]

Ниже приведены мои эффекты. Используется для извлечения данных из серверной части.

//effects.ts

  loadCourierItems$ = createEffect(() =>
    this.actions$.pipe(
      ofType(CourierItemActions.loadCourierItems),
      mergeMap(action =>
        this.defaultService.getCourierItems(
        ).pipe(
          map(CourierItems => CourierItemActions.loadCourierItemsSuccess({ CourierItems })),
          catchError(error =>
            of(CourierItemActions.loadCourierItemsFailure({ error }))
          )
        )
      )
    )
  )

Ниже приводится мой селектор

//selector.ts

  export const selectCourierItemState = createFeatureSelector<CourierItemState>(
  CourierItemsFeatureKey
);

export const selectCourierItems = createSelector(selectCourierItemState, selectAll);

Это компонент, в который я отправляю действие для получения данных в первый раз:

//app.component.ts

  constructor(private store: Store<CourierItemsState>) {
    this.store.dispatch(loadCourierItems())
  }

ngOnInit() {
this.courierItems$ = this.store.pipe(select(selectCourierItems))
}
//template.html


<div *ngFor="let item of courierItems$ | async as courier>
<p>{{courier.name}}</p>
<p>{{courier.loc_cur}}</p>

etc...
</div>

...

Как я могу это сделать?

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

Обновлено

loadCourierItems$ = createEffect(() =>
this.actions$.pipe(
  ofType(CourierItemActions.loadCourierItems),
  exhaustMap(action => interval(1000).pipe(
    takeUntil(this.actions$.pipe(ofType(CourierItemActions.stopCourierItems))),
    exhaustMap(() =>
      this.defaultService.getCourierItems(
        action.limit,
        action.start,
        action.end,
      ).pipe(
        map(courierItems => CourierItemActions.loadCourierItemsSuccess({ courierItems })),
        catchError(error =>
          of(CourierItemActions.loadCourierItemsFailure({ error }))
        )
      )
    )
  ))
)
)

ДРУГОЕ ОБНОВЛЕНИЕ Если я использую что-то подобное, я могу получать каждую секунду, и коллекция сущностей растет , Но благодаря такому подходу я не могу контролировать запуск / останов.

    let date = 1587513626000; // date is required because the backend only sends data with a start and end date
    interval(1000).pipe(tap(_ => {
      this.store.dispatch(loadStoreItems({ limit: 10, start: date, end: date + 1000 }))
      date += 1000
    }))
      .subscribe()

ОБНОВЛЕНИЕ РЕДУКТОРА

export const reducer = createReducer(
    initialState,
    on(CourierItemActions.loadCourierItemsSuccess,
      (state, action) => adapter.addMany(action.courierItems, state)
    ),
    on(CourierItemActions.loadCourierItemsFailure,
      (state, action) => {
        return {
          ...state,
          error: action.error
        }
      }
    ),

Я пробовал addMany & addAll .. Оба не работают. Только элементы первого вызова попадают в коллекцию сущностей. Но в фоновом режиме запрос все еще продолжается каждые 1 с.

ОБНОВЛЕНИЕ Это селектор.

export const selectCourierItemState = createFeatureSelector<CourierItemState>(
    CourierItemsFeatureKey
  );

  export const selectCourierItems = createSelector(selectCourierItemState, selectAll);

1 Ответ

1 голос
/ 25 апреля 2020

Если вам нужен эффект для отправки запроса каждую секунду - вам нужен оператор interval.

//effects.ts

loadCourierItems$ = createEffect(() =>
  this.actions$.pipe(
    ofType(CourierItemActions.loadCourierItems),
    exhaustMap(action => interval(1000).pipe(
      startWith(0),
      exhaustMap(step =>
        this.defaultService.getCourierItems(
          action.limit,
          action.start + step * 1000,
          action.end + step * 1000,
        ).pipe(
          map(courierItems => CourierItemActions.loadCourierItemsSuccess({ courierItems })),
          catchError(error =>
            of(CourierItemActions.loadCourierItemsFailure({ error }))
          )
        )
      ),
    ),
    takeUntil(this.actions$.pipe(ofType(CourierItemActions.pauseStreamingCourierItems))),
    repeat(),
  )
)
//app.component.ts

  constructor(private store: Store<CourierItemsState>) {
  }

  ngOnInit() {
    this.store.dispatch(loadCourierItems());
    this.courierItems$ = this.store.pipe(select(selectCourierItems));
  }

  ngOnDestroy() {
    this.store.dispatch(stopCourierItems());
  }
...