ReactJS实现按自定义规则而非字母序排序分类对象
自定义React分类列表的排序顺序
问题背景
现有分类后的食品数据(结构如下),当前React代码按字母序排序分类,需要实现自定义分类顺序(如BREAKFAST > LUNCH > DINNER > ALCOHOL),让指定分类优先展示。
数据结构示例
{ "ALCOHOL": { "items": [ { "Category": "ALCOHOL", "Name": "Beer - Can", "Quantity": "1", "Weight": 0.4, "bought": false, "packed": false, "id": "748eeb60-15da-11ec-b278-b1ac8c1941a3" }, { "Category": "ALCOHOL", "Name": "Gin & Tonic - Can", "Quantity": "1", "Weight": 0.27, "bought": false, "packed": false, "id": "778f0c00-15da-11ec-b278-b1ac8c1941a3" } ] }, "BREAKFAST": { "items": [ { "Category": "BREAKFAST", "Name": "Chobani Pouch 100g", "Quantity": "1", "Weight": "0.100", "bought": false, "packed": false, "id": "KqoCRUAm0lDIszxbvCQ2" }, { "Category": "BREAKFAST", "Name": "Milk - Fresh (1L)", "Quantity": "1", "Weight": 1.065, "bought": false, "packed": false, "id": "75c5e4c0-15da-11ec-b278-b1ac8c1941a3" } ] } }
当前代码片段
const categorizedDataFoods1 = foodValue.reduce((acc, curr) => { const { id, Category, Name, Quantity, Weight, packingLocation, bought, packed } = curr; if (!acc[Category]) { acc[Category] = { items: [], }; } acc[Category].items.push({ Category, Name, Quantity, Weight, packingLocation, bought, packed, id }); return acc; }, {}); {Object.keys(categorizedDataFoods1).map((key, index) => { return ( {categorizedDataFoods1[key]?.items .sort(function (aa, ab) { var categoryA = aa.Category.toUpperCase(); var categoryB = ab.Category.toUpperCase(); if (categoryA !== categoryB) { return categoryA < categoryB ? -1 : 1; } var nameA = aa.Name.toUpperCase(); var nameB = ab.Name.toUpperCase(); if (nameA !== nameB) { return nameA < nameB ? -1 : 1; } }) .map((checkbox, index) => { {checkbox.Name} }})})}
解决方案
核心思路是通过自定义优先级映射表,对比分类在映射表中的索引值实现排序,具体步骤如下:
1. 定义自定义排序优先级数组
创建一个按期望顺序排列的分类数组,数组索引即为优先级(索引越小,排序越靠前):
const customCategoryOrder = ['BREAKFAST', 'LUNCH', 'DINNER', 'ALCOHOL'];
2. 对分类键进行排序
不再直接遍历原始分类键,先对分类键按自定义顺序排序:
const sortedCategories = Object.keys(categorizedDataFoods1).sort((a, b) => { // 获取分类在自定义列表中的索引,未定义的分类默认排到最后 const indexA = customCategoryOrder.indexOf(a); const indexB = customCategoryOrder.indexOf(b); return (indexA === -1 ? Infinity : indexA) - (indexB === -1 ? Infinity : indexB); });
3. 修改渲染逻辑
用排序后的sortedCategories替代原始分类键数组进行遍历,同时保留内部物品的名称排序逻辑:
{sortedCategories.map((key, index) => { return ( <section key={key} className="category-group"> <h2>{key}</h2> {categorizedDataFoods1[key].items .sort((aa, ab) => aa.Name.toUpperCase().localeCompare(ab.Name.toUpperCase())) .map(item => ( <div key={item.id} className="food-item"> {item.Name} </div> ))} </section> ); })}
完整优化代码示例
const customCategoryOrder = ['BREAKFAST', 'LUNCH', 'DINNER', 'ALCOHOL']; const categorizedDataFoods1 = foodValue.reduce((acc, curr) => { const { id, Category, Name, Quantity, Weight, packingLocation, bought, packed } = curr; if (!acc[Category]) { acc[Category] = { items: [], }; } acc[Category].items.push({ Category, Name, Quantity, Weight, packingLocation, bought, packed, id }); return acc; }, {}); // 按自定义顺序排序分类 const sortedCategories = Object.keys(categorizedDataFoods1).sort((a, b) => { const indexA = customCategoryOrder.indexOf(a); const indexB = customCategoryOrder.indexOf(b); return (indexA === -1 ? Infinity : indexA) - (indexB === -1 ? Infinity : indexB); }); // 渲染组件 return ( <div className="food-list"> {sortedCategories.map((key) => ( <section key={key} className="category-section"> <h3>{key}</h3> {categorizedDataFoods1[key].items .sort((aa, ab) => aa.Name.toUpperCase().localeCompare(ab.Name.toUpperCase())) .map(item => ( <div key={item.id} className="food-item"> {item.Name} </div> ))} </section> ))} </div> );
补充说明
- 未出现在
customCategoryOrder中的分类,会自动排到所有自定义分类之后,如需调整这部分排序,可在sort函数中补充额外逻辑。 - 使用
localeCompare替代手动字符串对比,代码更简洁且支持多语言场景。
内容的提问来源于stack exchange,提问作者Paul VI
相关产品推荐
相关产品推荐

