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

如何过滤复杂JSON结构并在React中渲染层级菜单?

餐饮菜单层级结构整理与React渲染实现方案

一、数据转换逻辑

首先需要将原始JSON数据转换为目标的层级结构,通过两次reduce方法完成映射与分组:

原始数据结构示例(假设)

{
  "menuSections": [
    { "id": "section1", "name": "热菜区" },
    { "id": "section2", "name": "凉菜区" }
  ],
  "menus": [
    {
      "id": "menu1",
      "sectionId": "section1",
      "name": "川味系列",
      "items": [
        {
          "id": "item1",
          "name": "水煮鱼",
          "menuItemIds": 2,
          "subItems": ["麻辣味", "藤椒味"]
        },
        {
          "id": "item2",
          "name": "回锅肉",
          "menuItemIds": 1,
          "subItems": []
        }
      ]
    },
    {
      "id": "menu2",
      "sectionId": "section2",
      "name": "清爽小菜",
      "items": [
        {
          "id": "item3",
          "name": "拍黄瓜",
          "menuItemIds": 3,
          "subItems": ["蒜末味", "酸辣味"]
        }
      ]
    }
  ]
}

转换函数实现

const transformMenuData = (rawData) => {
  // 构建分区ID到名称的映射表,快速查找分区名称
  const sectionMap = rawData.menuSections.reduce((map, section) => {
    map[section.id] = section.name;
    return map;
  }, {});

  // 按分区分组,整理为「分区→菜单→菜品→子菜品」结构
  return rawData.menus.reduce((result, menu) => {
    const sectionName = sectionMap[menu.sectionId];
    if (!result[sectionName]) {
      result[sectionName] = [];
    }
    result[sectionName].push({
      menuName: menu.name,
      dishes: menu.items.map(item => ({
        dishName: `${item.name} (x${item.menuItemIds})`,
        subItems: item.subItems
      }))
    });
    return result;
  }, {});
};

二、React分层渲染组件

采用组件拆分的方式,每个组件负责单一层级的渲染,保证代码可维护性:

import React from 'react';

// 子菜品项组件
const SubItem = ({ name }) => (
  <li style={{ marginLeft: '20px', listStyle: 'circle' }}>{name}</li>
);

// 菜品项组件(包含数量与子菜品)
const DishItem = ({ dish }) => (
  <li>
    {dish.dishName}
    {dish.subItems.length > 0 && (
      <ul>
        {dish.subItems.map((sub, idx) => <SubItem key={idx} name={sub} />)}
      </ul>
    )}
  </li>
);

// 菜单列表组件(对应某个菜单下的所有菜品)
const MenuList = ({ menu }) => (
  <div style={{ marginLeft: '15px' }}>
    <h4>{menu.menuName}</h4>
    <ul>
      {menu.dishes.map((dish, idx) => <DishItem key={idx} dish={dish} />)}
    </ul>
  </div>
);

// 分区菜单组件(对应某个分区下的所有菜单)
const SectionMenu = ({ sectionName, menus }) => (
  <div>
    <h3>{sectionName}</h3>
    {menus.map((menu, idx) => <MenuList key={idx} menu={menu} />)}
  </div>
);

// 主菜单组件
const RestaurantMenu = ({ rawData }) => {
  const menuData = transformMenuData(rawData);

  return (
    <div style={{ padding: '2rem' }}>
      {Object.entries(menuData).map(([section, menus], idx) => (
        <SectionMenu key={idx} sectionName={section} menus={menus} />
      ))}
    </div>
  );
};

// 使用示例
const rawMenuData = { /* 填入你的原始JSON数据 */ };

export default function App() {
  return <RestaurantMenu rawData={rawMenuData} />;
}

三、注意事项

  • 如果原始数据的字段名和示例不一致,只需修改转换函数中对应的字段引用即可
  • 内联样式仅为示例,实际项目建议替换为CSS Modules或Tailwind等样式方案
  • 可以根据需求添加展开/收起功能,只需给对应层级组件增加状态控制即可

内容的提问来源于stack exchange,提问作者user15042889

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 08:45:49