簡體   English   中英

ngrx 8:從reducer 函數訪問@ngrx/data 實體的狀態

[英]ngrx 8: Access state of @ngrx/data entity from reducer function

我需要在 reducer 函數中訪問 ngrx/data 實體的狀態。

我正在構建一個尋呼機(分頁),用戶可以在其中導航到最后一頁以及其他選項。 但是我不知道緩存中有多少項, EntitySelectorsFactory有( selectCount ),但我不想在組件中獲取數據並使用 props 來傳遞它們,而是它們應該在 reducer 中。

或者也許有更好的方法。

行動

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 實體的狀態,獲取其實際值,或更優雅的方法。

這是一個不直接回答問題的答案。 相反,我采用了不同的方法,最初是第一種方法。 它不是那么優雅,但為了可重用性,我會將這些功能放入單獨的服務中。

功能是

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

我更喜歡保持我的組件清潔...我看到了兩種解決您問題的方法

  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. 您可以保留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 });         
      })
    )
  ); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM