
在 reselect 中,用闭包动态创建 memoized selector 会导致每次渲染都新建 selector 实例,使缓存失效、重复执行计算逻辑,带来显著性能损耗。
Reselect 的核心优势在于其基于输入参数的智能缓存机制(即 recomputations 和 memoized 结果复用)。但这一机制的前提是:selector 实例必须稳定复用——即同一 selector 函数在多次调用中保持引用一致,才能正确比对前序输入并命中缓存。
❌ 闭包方式:每次渲染都新建 selector(性能隐患)
const selectOrdersByCustomer = customerId =>
createSelector(
state => state.orders,
orders => {
console.count('⚠️ output selector executed'); // 每次都会触发!
return orders.filter(order => order.customerId === customerId);
}
);
// 在组件中:
const orders = useSelector(selectOrdersByCustomer(customerId));问题在于:selectOrdersByCustomer(customerId) 每次调用都返回一个全新 selector 实例。即使 customerId 相同,useSelector 接收到的是不同函数引用,Reselect 无法关联历史缓存;更严重的是,该 selector 内部的 state => state.orders 输入选择器也随 selector 实例重建而“重置”,导致缓存完全失效。
如实验日志所示:
⚠️ output selector executed: 1 ⚠️ output selector executed: 2 ⚠️ output selector executed: 3 → 返回结果不相等(s1 !== s2),recomputations 累计为 3
这不仅浪费 CPU(重复 filter),还可能引发不必要的组件重渲染(尤其当返回新数组时,浅比较失败)。
✅ 标准方式:参数化 selector(推荐实践)
const selectOrdersByCustomer = createSelector(
state => state.orders,
(state, customerId) => customerId, // 显式声明第二个输入选择器
(orders, customerId) => {
console.count('✅ memoized output selector'); // 仅首次或输入变更时执行
return orders.filter(order => order.customerId === customerId);
}
);
// 组件中稳定复用同一 selector 实例:
const orders = useSelector(state => selectOrdersByCustomer(state, customerId));✅ 此写法中,selectOrdersByCustomer 是单例函数,useSelector 始终接收相同引用;Reselect 能正确追踪 (state.orders, customerId) 的组合变化,仅当 state.orders 数组变更 或 customerId 改变时才重新计算,并复用上一次结果。
实验验证:
✅ memoized output selector: 1 → recomputations() === 1,且 x1 === x2 === x3(返回同一数组引用)
⚠️ 注意事项与优化建议
- 避免在 render 中调用工厂函数:如 selectXxx(param)、makeSelector(param) 等模式均会破坏 selector 稳定性;
- 若需多参数,统一通过 (state, props) 传入:Reselect v5+ 支持 props 作为第二参数,与 Redux Toolkit 的 createSelector 兼容;
- 结合 useMemo 非必要:不要试图用 useMemo(() => selectXxx(id), [id]) “优化”闭包 selector——这仍会生成新函数,且增加额外开销;
- 检查 selector 引用稳定性:可在组件内 useEffect(() => { console.log(selectOrdersByCustomer) }, []) 验证是否始终为同一函数。
总之,Reselect 的性能收益高度依赖 selector 实例的持久性。坚持使用参数化(而非闭包工厂)模式,是保障 memoization 有效、避免隐式性能退化的关键实践。











