NGRX - комбинируйте селекторы с реквизитом

Как комбинировать редукторы, когда одному из них нужен реквизит?

У меня следующая модель:

interface Device {
  id: string;
  data: IDeviceData;
}

и DeviceReducer, который выглядит следующим образом:

import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { Device } from '../model/device';
import { SubnetBrowserApiActions } from 'src/app/explorer/actions';

export interface State extends EntityState<Device> { }

export const adapter: EntityAdapter<Device> = createEntityAdapter<Device>();

export const initialState: State = adapter.getInitialState();

export function reducer(
  state = initialState,
  action:
    | SubnetBrowserApiActions.SubnetBrowserApiActionsUnion
): State {
  switch (action.type) {
    case SubnetBrowserApiActions.SubnetBrowserApiActionTypes.LoadEntriesSucces: {
      return adapter.upsertMany(action.payload.entries, state);
    }

    default: {
      return state;
    }
  }
}

const {
  selectAll,
} = adapter.getSelectors();

export const getAllDevices = selectAll;

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

export const getVisibleDrives = createSelector(
  [fromRoot.getAllDevices, getVisibleDrivesSerialNumbers],
  (devices, visibleDevicesIds) =>
    devices.filter((device) => onlineDevicesIds.includes(device.serialNumber)),
);

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

Дополнительный селектор в DeviceReduced

export const getDrivesWithIds = (ids: string[]) => createSelector(
  getAllDevices,
  devices => devices.filter(device => ids.includes(device.id))
);

А затем объедините их следующим способом:

export const getVisibleDrives = createSelector(
  getVisibleDrivesSerialNumbers,
  (ids) => fromRoot.getDrivesWithIds
);

Проблема здесь в том, что возвращаемый тип этого селектора

(ids: string[]) => MemoizedSelector<State, Device[]>

Что лишает меня возможности делать что-нибудь полезное с этим селектором. В качестве примера я хотел бы отфильтровать этот список по ключевому слову, и я не могу использовать для него метод filter:

Пример использования

export const getFilteredVisibleDrives = createSelector(
  [getVisibleDrives, getKeywordFilterValue],
  (visibleDrives, keywordFilter) => {
    return visibleDrives
      .filter(drive => // in this line there is an error: Property 'filter' does not exist on type '(ids: string[]) => MemoizedSelector<State, Device[]>'
        drive.ipAddress.toLowerCase().includes(keywordFilter.toLowerCase()) ||
        drive.type.toLowerCase().includes(keywordFilter.toLowerCase()) ||
        drive.userText.toLowerCase().includes(keywordFilter.toLowerCase())
      );
  },
);

person bartosz.baczek    schedule 15.02.2019    source источник


Ответы (1)


Селектор:

export const getCount = () =>   
  createSelector(     
    (state, props) => state.counter[props.id],     
    (counter, props) => counter * props.multiply
  );

Составная часть:

this.counter2 = this.store.pipe(
  select(fromRoot.getCount(), { id: 'counter2', multiply: 2 })
);   
this.counter4 = this.store.pipe(
  select(fromRoot.getCount(), { id: 'counter4', multiply: 4 })
);

Дополнительную информацию см. В моем сообщении NgRx: параметризованные селекторы.

person timdeschryver    schedule 15.02.2019
comment
как это работает в случае, когда вы можете определить редукторы на уровне Feature, а затем сделать их глобальными вне функции? Я пробовал, но не работает: gist.github.com/mindscratch/22d507f840127db9f7 - person codecraig; 08.01.2021