You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 08:45:21