1

我需要在 reducer 函数中访问 ngrx/data 实体的状态。

我正在构建一个寻呼机(分页),用户可以在其中导航到最后一页以及其他选项。但我不知道缓存中有多少项目,EntitySelectorsFactorydoes( 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动作中传递该计数。另一种选择是副作用,但它们令人困惑,恕我直言不是编写代码的正确方法(不可读的代码,缺少直接原因/结果,是的,我知道,我不想争论它)。然后,即使创建了一个副作用,如何在模块中定义它?它会是AppEffects副作用还是明显的副作用?我猜 AppEffects 因为它不在另一个模块中。

app.module.ts

    EffectsModule.forRoot([AppEffects]),

AppEffects = 几乎是空的,默认ng add内容。

所以是的,我需要在 reducer 中获取 @ngrx/data 实体的状态,获取它的实际值,或更优雅的方法。

4

2 回答 2

1

这是一个不直接回答问题的答案。相反,我采用了不同的方法,最初是第一种方法。它没有那么优雅,但为了可重用性,我会将这些功能放入单独的服务中。

功能是

  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());
  }

一个真的只需要getter和setter。便利功能似乎在 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)
);
于 2020-01-16T21:42:56.657 回答
1

我更喜欢让我的组件保持清洁......我看到了两种解决您问题的方法

  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)}),

}
  1. 您可以在 reducer 中保留toEnd action而不使用它,而是构建一个被调用的效果,toEnd action从 store 的另一部分获取您需要的值,然后调用第二个 action 将值传递给 reducer。
  toEndPager$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PagerActions.toEnd),
      withLatestFrom(this.store.select(rantSelectors.selectEntities.length)),
      switchMap(([{},length]) => {
        return of(PagerActions.toEndSuccess({ length });         
      })
    )
  ); 
于 2020-01-17T08:23:40.103 回答