NGRX 如何在createSelector内复用未提前获知入参的工厂selector
问题根源
你的写法有两个核心疏漏:
createSelector只能接收可直接传入state执行的selector实例作为依赖,你传入的selectA/selectAFactory是工厂函数本身,传入后投影函数拿到的只是工厂函数引用,调用它返回的是MemoizedSelector实例,不是计算结果。- 工厂selector生成的
MemoizedSelector实例必须主动传入当前state执行,才能拿到最终的状态计算值。
基础实现方案
最简单的改法是直接把全局状态作为依赖,在投影函数内主动执行每个id对应的selector:
// 注意替换AppState为你项目里的根状态类型 const selectListOfA = (ids: number[]) => createSelector( (state: AppState) => state, (state) => { return ids.map((id) => selectA(id)(state)); } );
这种写法可以直接拿到你要的状态数组,不需要额外封装工厂,但缺点是全局状态任意变更都会触发列表重计算, memoization 效率不高。
带缓存优化的实现方案
如果要保留memoization能力,避免不必要的重计算,可以把selectA的核心计算逻辑抽成公共纯函数,两边复用:
// 1. 抽离公共计算逻辑,完全复用原来selectA投影函数的代码 const computeA = (thing1: Thing1Type, thing2: Thing2Type, thing3: Thing3Type) => { // 这里直接写你原来selectA投影函数里的return逻辑 return ... }; // 2. 原单id的selectA复用逻辑 const selectA = (id: number) => createSelector( selector1.selectEntityMap, selector2.selectEntityMap, selector3ById(id), computeA ); // 3. 列表selector复用相同逻辑,同时保证缓存效率 const selectListOfA = (ids: number[]) => createSelector( selector1.selectEntityMap, selector2.selectEntityMap, selector3.selectEntityMap, // 直接取selector3的全量实体映射 (thing1Map, thing2Map, thing3Map) => { return ids.map((id) => computeA(thing1Map, thing2Map, thing3Map[id])); } );
这种写法只有当selectA依赖的三个上游状态发生变更时,才会触发列表重计算,缓存效率和原来的单id selector完全一致。
内容的提问来源于stack exchange,提问作者Tr1stan
相关产品推荐
相关产品推荐

