Reselect如何在combiner前将一个选择器结果作为参数传入另一选择器
实现方法
你需要先新增一个支持按货运单ID列表过滤的记忆化事件选择器,替代直接返回全量事件的packageEvents,再调整目标选择器的输入逻辑,把前序步骤拿到的货运单ID传入事件选择器做过滤即可。
步骤1:定义按ID过滤的事件选择器
这个选择器接收全局state和货运单ID列表,只返回匹配ID的关联事件,本身带记忆化缓存,不会重复计算:
const packageEventsByShipmentIds = createImmutableEqualSelector( [ packageEvents, // 复用原有全量事件选择器,本身有缓存不会重复拉取 (_state: AppStateType, shipmentIds: List<number>) => shipmentIds ], (allEvents, shipmentIds) => allEvents.filter( event => shipmentIds.includes(event.get('shipmentId')) // 如果你的事件关联货运单的字段名不是shipmentId,对应调整这里的取值逻辑即可 ) )
步骤2:改造目标货运单选择器
这里提供两种兼容写法,根据你使用的reselect版本选即可:
写法1:适配reselect v4+(支持输入选择器获取前序返回值)
export const shipmentsRejectedSelector: ( state: AppStateType, departmentIds: List<number>, currentDate: DateTime, toDate: DateTime ) => List<Shipment> = createImmutableEqualSelector( // 第一步:拿指定部门、时间范围的货运单 shipmentsByDepartmentIdsAndDate, // 第二步:从第一步返回的货运单里提取ID,查询对应关联事件 (state, shipments) => { const shipmentIds = shipments.valueSeq().map(s => s.get('id')).toList() return packageEventsByShipmentIds(state, shipmentIds) }, // 第三步:计算最终结果,顺便修正原代码里括号闭合错误、非严格相等的问题 (shipments, _events) => shipments.valueSeq() .filter(s => s.get('state') === EventType.REJECTED) ?.toList() || List() )
写法2:兼容低版本reselect
如果你的reselect版本低于v4,不支持输入选择器读取前序返回值,可以用下面的写法,性能完全一致——因为记忆化选择器参数不变时会直接返回缓存,不会重复执行计算:
export const shipmentsRejectedSelector: ( state: AppStateType, departmentIds: List<number>, currentDate: DateTime, toDate: DateTime ) => List<Shipment> = createImmutableEqualSelector( shipmentsByDepartmentIdsAndDate, (state, departmentIds, currentDate, toDate) => { const shipments = shipmentsByDepartmentIdsAndDate(state, departmentIds, currentDate, toDate) const shipmentIds = shipments.valueSeq().map(s => s.get('id')).toList() return packageEventsByShipmentIds(state, shipmentIds) }, (shipments, _events) => shipments.valueSeq() .filter(s => s.get('state') === EventType.REJECTED) ?.toList() || List() )
说明:上述代码已经修正了你原代码里filter后多余的闭合括号,同时将非严格相等
==替换为严格相等===,符合TypeScript类型校验的最佳实践。
内容的提问来源于stack exchange,提问作者Ludwig
相关产品推荐
相关产品推荐

