如何在mapState中使用Reselect组合选择器计算总和?
用Reselect组合选择器的正确姿势
首先得说,你原来的写法有两个核心问题:一是在mapState里直接创建createSelector会导致每次组件更新都生成新的选择器,完全浪费了Reselect的缓存优化能力;二是不能把mapState里的局部变量sub1、sub2作为createSelector的依赖——Reselect的依赖必须是能从state/ownProps提取数据的纯函数才行。
正确的做法是把选择器的定义放在mapState外部,下面分两种常用场景给你示例:
场景1:固定获取sub1和sub2的值
如果你的sub1和sub2是固定的key(比如永远取state里的sub1和sub2字段),可以直接定义独立的子选择器,再组合成total选择器:
import { createSelector } from 'reselect'; // 第一步:定义基础的子选择器 const selectSub1 = createSelector( // 第一个参数:从state中获取原始数据的函数(替换成你实际的state路径) (state) => state.yourTargetData, // 第二个参数:处理数据的纯函数,返回最终的sub1值 (data) => data.sub1 || 0 ); const selectSub2 = createSelector( (state) => state.yourTargetData, (data) => data.sub2 || 0 ); // 第二步:组合成total选择器,依赖上面两个子选择器 const selectTotal = createSelector( selectSub1, selectSub2, // 最后一个参数:计算逻辑,接收前面依赖的结果 (sub1, sub2) => ({ total: sub1 + sub2 }) ); // 第三步:在mapState里直接调用这些预定义的选择器 export const mapState = (state) => { return { sub1: selectSub1(state), sub2: selectSub2(state), total: selectTotal(state) }; };
场景2:需要根据ownProps动态指定key
如果你的子选择器需要根据组件的ownProps动态选择key(比如不同组件实例取不同的sub字段),就得用工厂函数+memoize来缓存生成的选择器,避免重复创建:
import { createSelector, memoize } from 'reselect'; // 工厂函数:根据传入的key生成对应的子选择器,用memoize缓存已生成的选择器 const makeSubSelector = memoize((key) => createSelector( (state) => state.yourTargetData, (data) => data[key] || 0 )); // 工厂函数:根据两个key生成total选择器 const makeTotalSelector = memoize((key1, key2) => createSelector( makeSubSelector(key1), makeSubSelector(key2), (sub1, sub2) => ({ total: sub1 + sub2 }) )); // 在mapState里使用(支持ownProps动态传参) export const mapState = (state, ownProps) => { // 这里可以根据ownProps动态传key,比如ownProps.subKey1、ownProps.subKey2 const sub1 = makeSubSelector('sub1')(state); const sub2 = makeSubSelector('sub2')(state); const total = makeTotalSelector('sub1', 'sub2')(state); return { sub1, sub2, total }; };
关键提醒
- 绝对不要在
mapState或者组件内部的渲染函数里直接调用createSelector——每次渲染都会生成新的选择器,Reselect的缓存机制就彻底失效了,相当于白用。 - 所有选择器的依赖都必须是纯函数,只依赖
state和ownProps,这样Reselect才能正确判断是否需要重新计算结果。
内容的提问来源于stack exchange,提问作者Shawn Matthews
相关产品推荐
相关产品推荐

