
reselect 的推荐用法是将参数作为第二个参数传入 createselector,而非用闭包返回新 selector;后者每次渲染都会创建全新 selector 实例,导致缓存失效、重复计算,带来显著性能损耗。
在使用 Reselect 构建 Redux 状态选择器时,正确利用其 memoization 机制对应用性能至关重要。官方推荐的参数化 selector 写法如下:
const selectOrdersByCustomer = createSelector( state => state.orders, (state, customerId) => customerId, (orders, customerId) => orders.filter(order => order.customerId === customerId) ); // 在组件中调用: const orders = useSelector(state => selectOrdersByCustomer(state, customerId));
该模式下,selectOrdersByCustomer 是单个共享的 memoized selector 实例,其内部缓存(基于输入组合的 recomputations 和 lastResult)可跨多次调用复用。只要 state.orders 和 customerId 均未变化,输出函数(filter)将完全跳过执行。
而闭包式写法看似简洁,实则违背了 Reselect 的设计前提:
const selectOrdersByCustomer = customerId =>
createSelector(
state => state.orders,
orders => orders.filter(order => order.customerId === customerId)
);
// ❌ 错误用法:每次调用都新建 selector
const orders = useSelector(selectOrdersByCustomer(customerId));问题在于:selectOrdersByCustomer(customerId) 每次执行都会返回一个全新的 selector 函数。即使 customerId 相同,每个 selector 都拥有独立的缓存空间,且因组件重渲染频繁触发(如 props 变化、父组件更新),导致:
- 每次渲染都创建新 selector 实例(内存开销 + 初始化成本);
- 缓存永远无法命中(recomputations() 持续递增);
- 输出函数被反复执行(console.count 显示次数随渲染次数线性增长);
- 返回值引用不相等(s1 === s2 为 false),可能触发不必要的子组件重渲染(尤其配合 React.memo 时)。
✅ 正确实践要点:
- 始终复用 selector 实例:定义在模块顶层,避免在组件内或 selector 工厂中动态创建;
- 参数通过第二参数传递:利用 Reselect 对 (state, ...args) 的原生支持;
- 如需多个参数,可封装为对象(如 { customerId, status }),保持 selector 稳定性;
- 若必须动态生成 selector(极少数场景),应配合 useMemo 缓存闭包结果,但通常不必要且易出错。
总结:闭包式 selector 看似灵活,实则是典型的「伪优化」——牺牲 Reselect 的核心优势(结构共享 + 引用缓存)换取代码表层简洁。在中大型应用中,这类写法会快速演变为性能瓶颈。坚持官方推荐模式,才能真正发挥 Reselect 的 memoization 效能。











