React+TypeScript中合并相同游戏数据项的优化方案咨询
问题背景
我在React/TypeScript项目里实现一个功能:从接口获取包含key、value、quantity等字段的JSON数据,渲染成网格tiles;用户点击tile时,将该项加入gameData数组用于列表展示,重复点击同一项时需要合并数据——quantity累加、value累加。
现有数据结构示例:
const apiData = [ {key: 'A', value: 50, quantity: 1, color: '#3498db', ...etc}, {key: 'B', value: 40, quantity: 1, color: '#e67e22', ...etc}, ... ] const gameData = [ {key: 'A', value: 200, quantity: 4, color: '#3498db', ...etc}, {key: 'E', value: 10, color: '#fa0', ...etc}, ]
我用Array.reduce写了一个groupBy函数实现合并逻辑,功能正常,但觉得还有优化空间,想请教有哪些改进思路?
我的现有实现:
export function groupBy(array: GameData[]) { const group: GameData[] = Object.values( array.reduce((acc: any, { value, quantity, ...r }) => { const key = Object.entries(r).join("-"); acc[key] = acc[key] || { ...r, quantity: 0, value: 0 }; return ((acc[key].value += value), (acc[key].quantity += 1)), acc; }, {}) ); return group; }
几个实用的优化方向
1. 用天然唯一标识替代拼接key
你现在用剩余属性r的所有键值对拼接成分组key,存在潜在风险:如果r里有包含-的字段值,或者后续接口字段顺序调整,都会导致key失效。而数据里的key字段(比如'A'、'B')本身就是天然的唯一标识,直接用它作为分组key更高效可靠:
export function mergeGameDataItems(array: GameData[]) { return Object.values( array.reduce((acc: Record<string, GameData>, item) => { const existingItem = acc[item.key]; if (existingItem) { // 注意:原来的quantity +=1 是固定加1,改成累加item的quantity更通用(适配api返回quantity>1的情况) existingItem.quantity += item.quantity; existingItem.value += item.value; } else { acc[item.key] = { ...item }; // 直接拷贝原item,省去解构开销 } return acc; }, {}) ); }
2. 消除any类型,强化TypeScript类型安全
原代码里的acc: any会丢失类型检查,换成Record<string, GameData>可以让编译器帮你提前发现类型错误,代码更健壮:
// 假设GameData是你定义的类型,直接用Record<string, GameData>作为累加器类型 export function mergeGameDataItems(array: GameData[]) { return Object.values( array.reduce((acc: Record<string, GameData>, item) => { // ... 逻辑同上 }, {}) ); }
3. 减少不必要的性能开销
原代码中的{ value, quantity, ...r }解构、Object.entries(r).join("-")拼接都是额外的性能消耗,尤其是数据量较大时。直接使用item.key作为分组key,能省去这些冗余操作,提升运行效率。
4. 函数命名更具语义化
groupBy这个名字太通用,换成mergeGameDataItems或者aggregateTileSelections,能让其他开发者一眼看懂函数的功能,提升代码可读性和维护性。
5. 适配Immutable状态管理(可选)
如果你的gameData是用React状态管理(比如useState),且希望保持Immutable(不修改原对象),更新时要创建新对象而非直接修改现有对象,避免状态更新不触发的问题:
if (existingItem) { acc[item.key] = { ...existingItem, quantity: existingItem.quantity + item.quantity, value: existingItem.value + item.value }; } else { acc[item.key] = { ...item }; }
内容的提问来源于stack exchange,提问作者Shawn Sheehan

