ngrx 8: состояние доступа к @ ngrx / объекту данных из функции редуктора - PullRequest
1 голос
/ 16 января 2020

Мне нужно получить доступ к состоянию сущности ngrx / data в функции редуктора.

Я создаю пейджер (нумерацию страниц), где пользователь может перейти к последней странице среди других опций. Но я не знаю, сколько элементов в кэше есть, EntitySelectorsFactory делает (selectCount), но я бы не хотел получать данные в компоненте и использовать реквизиты для их передачи, вместо этого они должны быть в редукторе.

Или, может быть, есть лучший способ.

Действия

import {createAction, props} from '@ngrx/store';

export const toStart = createAction('[Pager] To Start');
export const toEnd = createAction('[Pager] To End');
export const incrementPage = createAction('[Pager] Increment');
export const decrementPage = createAction('[Pager] Decrement');
export const setPage = createAction('[Pager] Set', props<{page: number}>());
export const setPageSize = createAction('[Pager] Set Page Size', props<{size: number}>());

Редукторы

import { Action, createReducer, on } from '@ngrx/store';
import * as PagerActions from '../actions/pager';
import {EntitySelectorsFactory} from '@ngrx/data';
import {Rant} from '../models/rant';

export const pagerFeatureKey = 'pager';

export interface State {
  page: number;
  pageSize: number;
}

export const initialState: State = {
  page: 1,
  pageSize: 10,
};

const rantSelectors = new EntitySelectorsFactory().create<Rant>('Rant');

const pagerReducer = createReducer(
  initialState,
  on(PagerActions.toStart, state => ({...state, page: 1})),
  on(PagerActions.toEnd, state => ({...state, page: Math.floor(rantSelectors.selectEntities.length / state.pageSize)})),
  on(PagerActions.setPage, (state, action) => ({...state, page: action.page})),
  on(PagerActions.incrementPage, state => ({...state, page: state.page + 1})), // TODO: check if out of bounds
  on(PagerActions.decrementPage, state => ({...state, page: state.page > 1 ? state.page - 1 : 1})),
  on(PagerActions.setPageSize, (state, action) => ({...state, pageSize: action.size}))
);

export function reducer(state: State | undefined, action: Action) {
  return pagerReducer(state, action);
}

Неважно, что я делаю в

  on(PagerActions.toEnd, state => ({...state, page: Math.floor(rantSelectors.selectEntities.length / state.pageSize)})),

это всегда 0. rantSelectors.selectCount.length или выше. Вероятно, потому, что длина равна 0. Мне также нужно знать длину или количество «разглагольствующих» сущностей в редукторе increment.

Я не знаю, как получить фактическое значение.

Я думаю ... есть селектор для счетчика сущностей и использовать реквизиты для передачи этого счетчика в действии toEnd. Другим вариантом может быть побочный эффект, но они сбивают с толку, и imho не является правильным способом написания кода (нечитаемый код, отсутствие непосредственной причины / следствия, да, я знаю, я не хочу спорить об этом). И затем, даже если создать побочный эффект, как определить его в модуле? Это будет AppEffects побочный эффект или явный побочный эффект? Я предполагаю, что AppEffects отсутствует, потому что его нет в другом модуле.

app.module.ts

    EffectsModule.forRoot([AppEffects]),

AppEffects = практически пусто, по умолчанию ng add содержимое.

Так что да, мне нужно получить состояние объекта @ ngrx / data в редукторе, получить его фактическое значение или более элегантный подход.

Ответы [ 2 ]

2 голосов
/ 17 января 2020

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

  1. Вы можете просто сохранить длину rantSelectors.selectEntities.length в этой части магазина, добавив число ценность для вашего государства. Когда вы загружаете / обновляете rantSelectors.selectEntities, вы также обновляете этот фрагмент магазина.
export interface State {
  page: number;
  pageSize: number;
  rantEntitiesSize: number;

// ...
   on(rantActions.loadSuccess, 
      rantActions.UpdateSuccess, //could include adding objects to the current loaded list
      rantActions.RemoveSuccess, //(negative number)
      (state, action) => 
        ({...state, rantEntitiesSize: (state.rantEntitiesSize + action)}),

}
Вы можете оставить toEnd action и не использовать его в редукторе, вместо этого создать эффект, который вызывается на toEnd action, который получает нужные вам значения из другой части хранилища, а затем вызывает второе действие, которое проходит значение для редуктора.
  toEndPager$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PagerActions.toEnd),
      withLatestFrom(this.store.select(rantSelectors.selectEntities.length)),
      switchMap(([{},length]) => {
        return of(PagerActions.toEndSuccess({ length });         
      })
    )
  ); 
1 голос
/ 17 января 2020

Это ответ, который не отвечает на вопрос напрямую. Вместо этого я выбрал другой подход, первый подход изначально. Это не так элегантно, но для повторного использования я помещу эти функции в отдельный сервис.

Функции:

  this.maxPages$ = this.store.select(selectMaximumRantPages);

  toStart() {
    this.store.dispatch(PagerActions.setPage({page: 1}));
  }
  toEnd() {
    this.maxPages$.subscribe(pages => {
      this.store.dispatch(PagerActions.setPage({page: pages}));
    }).unsubscribe();
  }
  setPage(page: number) {
    this.store.dispatch(PagerActions.setPage({page}));
  }
  setPageSize(size: number) {
    this.store.dispatch(PagerActions.setPageSize({size}));
  }
  increment() {
    this.store.dispatch(PagerActions.incrementPage());
  }
  decrement() {
    this.store.dispatch(PagerActions.decrementPage());
  }

На самом деле нужны только методы получения и установки. Удобные функции, кажется, не имеют места в мире ngrx. Я также избавлюсь от действий увеличения и уменьшения и реализую их как методы обслуживания.

селекторы

export const selectPagerPage = (state: State) => state.pager.page;
export const selectPagerPageSize = (state: State) => state.pager.pageSize;
export const selectMaximumRantPages = createSelector(
  selectPagerPageSize,
  rantSelectors.selectCount,
  (size, count) => Math.ceil(count / size)
);
...