NGRX - 结合选择器和道具
NGRX - combine selectors with props
当其中一个需要 props 时,如何组合 reducer?
我有以下型号:
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;
在我的另一个减速器中,当我想 select 使用 id 数组的设备时,我使用以下代码:
export const getVisibleDrives = createSelector(
[fromRoot.getAllDevices, getVisibleDrivesSerialNumbers],
(devices, visibleDevicesIds) =>
devices.filter((device) => onlineDevicesIds.includes(device.serialNumber)),
);
这段代码非常重复,所以我想添加参数化 select 或者这将 return 只有这些驱动器,它们在我作为道具传递的数组中具有 id。我尝试做的事情如下所示:
附加select或 DeviceReduced
export const getDrivesWithIds = (ids: string[]) => createSelector(
getAllDevices,
devices => devices.filter(device => ids.includes(device.id))
);
然后按以下方式组合它们:
export const getVisibleDrives = createSelector(
getVisibleDrivesSerialNumbers,
(ids) => fromRoot.getDrivesWithIds
);
这里的问题是这个 select 的 returned 类型或者是
(ids: string[]) => MemoizedSelector<State, Device[]>
这让我无法用这个 selector 做任何有用的事情。例如,我想按关键字过滤此列表,但我无法在其上使用 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())
);
},
);
看我的postNgRx: Parameterized selectors
获取更多信息。
更新:NgRx v13+
带道具的选择器已弃用,请改用选择器工厂:
选择器:
export const getCount = (props: {id: number, multiply:number}) =>
createSelector(
(state) => state.counter[props.id],
(counter) => 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 })
);
已弃用
选择器:
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 })
);
当其中一个需要 props 时,如何组合 reducer?
我有以下型号:
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;
在我的另一个减速器中,当我想 select 使用 id 数组的设备时,我使用以下代码:
export const getVisibleDrives = createSelector(
[fromRoot.getAllDevices, getVisibleDrivesSerialNumbers],
(devices, visibleDevicesIds) =>
devices.filter((device) => onlineDevicesIds.includes(device.serialNumber)),
);
这段代码非常重复,所以我想添加参数化 select 或者这将 return 只有这些驱动器,它们在我作为道具传递的数组中具有 id。我尝试做的事情如下所示:
附加select或 DeviceReduced
export const getDrivesWithIds = (ids: string[]) => createSelector(
getAllDevices,
devices => devices.filter(device => ids.includes(device.id))
);
然后按以下方式组合它们:
export const getVisibleDrives = createSelector(
getVisibleDrivesSerialNumbers,
(ids) => fromRoot.getDrivesWithIds
);
这里的问题是这个 select 的 returned 类型或者是
(ids: string[]) => MemoizedSelector<State, Device[]>
这让我无法用这个 selector 做任何有用的事情。例如,我想按关键字过滤此列表,但我无法在其上使用 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())
);
},
);
看我的postNgRx: Parameterized selectors 获取更多信息。
更新:NgRx v13+
带道具的选择器已弃用,请改用选择器工厂:
选择器:
export const getCount = (props: {id: number, multiply:number}) =>
createSelector(
(state) => state.counter[props.id],
(counter) => 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 })
);
已弃用
选择器:
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 })
);