如何过滤复杂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
相关产品推荐
相关产品推荐

