You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NGRX 如何在createSelector内复用未提前获知入参的工厂selector

问题根源

你的写法有两个核心疏漏:

  1. createSelector 只能接收可直接传入state执行的selector实例作为依赖,你传入的selectA/selectAFactory是工厂函数本身,传入后投影函数拿到的只是工厂函数引用,调用它返回的是MemoizedSelector实例,不是计算结果。
  2. 工厂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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 05:45:03