如何在ReactJS中获取层级JSON各级键并实现分类详情展示
React实现餐厅分类卡片及菜品详情展示
核心思路
- 用
Object.entries()将层级JSON对象转换为可遍历数组,解决嵌套对象的渲染问题 - 通过React状态
useState控制当前选中的分类,实现点击切换详情的交互 - 分区域渲染:先展示所有分类卡片,选中后渲染对应分类下的菜品详情
完整实现代码
import { useState, useEffect } from 'react'; const RestaurantMenu = () => { // 状态存储API数据、当前选中的分类 const [restaurantData, setRestaurantData] = useState(null); const [selectedCategory, setSelectedCategory] = useState(null); // 模拟API请求获取数据(实际项目替换为fetch/axios) useEffect(() => { const mockApiData = { "Categories": { "Breakfast": { "Poha": { "Description": "This is item description given by restaurant owner", "Likes": "123", "Image": "image url", "Price": 30 }, "Upma": { "Description": "Chunks of paneer, a type of fresh cheese, are marinated in spices and are then arranged on a stick with capsicums (bell peppers), onions and tomatoes. These sticks are grilled in a tandoor and the dish is thereafter served hot, seasoned with lemon juice and chaat masala.[8] It is sometimes accompanied by salad or mint chutney. Tikka dishes traditionally go well with mint chutney. The paneer, though tender, has a crisp singe on the surface.", "Likes": "35", "Image": "image url", "Price": 35 } }, "Starters": { "Chicken Bites": { "Description": "This is item description given by restaurant owner", "Likes": "55", "Image": "image url", "Price": 90 }, "Gobi Tikka": { "Description": "This is item description given by restaurant owner", "Likes": "9", "Image": "image url", "Price": 50 }, "Mashroom Tikka ": { "Description": "This is item description given by restaurant owner", "Likes": "87", "Image": "image url", "Price": 60 } }, "Chinese": { "Chicken Hakka Noodles": { "Description": "This is item description given by restaurant owner", "Likes": "525", "Image": "image url", "Price": 150 }, "Veg Schezwan Noodles ": { "Description": "This is item description given by restaurant owner", "Likes": "39", "Image": "image url", "Price": 140 }, "Veg Hakka Noodles": { "Description": "This is item description given by restaurant owner", "Likes": "90", "Image": "image url", "Price": 130 } }, "Main Course": { "Chicken Masala": { "Description": "This is item description given by restaurant owner", "Likes": "13", "Image": "image url", "Price": 340 }, "Paneer Tikka": { "Description": "Chunks of paneer, a type of fresh cheese, are marinated in spices and are then arranged on a stick with capsicums (bell peppers), onions and tomatoes. These sticks are grilled in a tandoor and the dish is thereafter served hot, seasoned with lemon juice and chaat masala.[8] It is sometimes accompanied by salad or mint chutney. Tikka dishes traditionally go well with mint chutney. The paneer, though tender, has a crisp singe on the surface.", "Likes": "34", "Image": "image url", "Price": 250 }, "Paneer Tikka Masala": { "Description": "This is item description given by restaurant owner", "Likes": "10", "Image": "image url", "Price": 260 } }, "Ice-creams": { "Chocolate": { "Description": "This is item description given by restaurant owner", "Likes": "12", "Image": "image url", "Price": 100 }, "Vanilla": { "Description": "This is item description given by restaurant owner", "Likes": "11", "Image": "image url", "Price": 100 }, "Creamy Milk": { "Description": "This is item description given by restaurant owner", "Likes": "13", "Image": "image url", "Price": 100 } } }, "Restaurant Details": { "Insta Profile link": "https://instaprofileurl.com", "Owner Contact": "+91 5007 227 997", "Restaurant Address": "Restaurant address", "Owner Name": "Mr. Owner Surname", "Restaurant website": "https://www.myrestaurant.com", "Owner Email ": "owner@gmail.com", "Facebook Profile link": "https://facebookprofileurl.com" }, "rid": "unique_restaurant_name" }; setRestaurantData(mockApiData); }, []); if (!restaurantData) return <div>Loading...</div>; // 将Categories对象转为[分类名, 菜品列表]的数组,方便遍历 const categories = Object.entries(restaurantData.Categories); return ( <div style={{ padding: '20px', maxWidth: '1200px', margin: '0 auto' }}> {/* 分类卡片区域 */} <div style={{ display: 'flex', gap: '15px', flexWrap: 'wrap', marginBottom: '30px' }}> {categories.map(([categoryName]) => ( <div key={categoryName} onClick={() => setSelectedCategory(categoryName === selectedCategory ? null : categoryName)} style={{ padding: '15px 25px', border: '1px solid #ddd', borderRadius: '8px', cursor: 'pointer', backgroundColor: selectedCategory === categoryName ? '#f0f0f0' : 'white', transition: 'background-color 0.2s' }} > <h3>{categoryName}</h3> </div> ))} </div> {/* 菜品详情区域 */} {selectedCategory && ( <div> <h2>{selectedCategory}</h2> <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))', gap: '20px' }}> {Object.entries(restaurantData.Categories[selectedCategory]).map(([itemName, itemDetails]) => ( <div key={itemName} style={{ border: '1px solid #ddd', borderRadius: '8px', padding: '15px' }}> <img src={itemDetails.Image} alt={itemName} style={{ width: '100%', height: '180px', objectFit: 'cover', borderRadius: '4px', marginBottom: '10px' }} /> <h3>{itemName}</h3> <p>₹{itemDetails.Price}</p> <p>Likes: {itemDetails.Likes}</p> <p style={{ fontSize: '14px', color: '#666', marginTop: '10px' }}>{itemDetails.Description}</p> </div> ))} </div> </div> )} </div> ); }; export default RestaurantMenu;
关键逻辑说明
- 数据遍历:
Object.entries()把嵌套对象转为键值对数组,比如Object.entries(restaurantData.Categories)会得到[["Breakfast", {Poha: ...}], ...],直接用map就能渲染分类。 - 状态切换:点击分类卡片时,切换
selectedCategory的值——再次点击同一分类会清空状态,隐藏详情。 - 条件渲染:只有当
selectedCategory有值时,才渲染对应的菜品详情区域。 - 基础样式:用内联样式实现简单布局,实际项目可替换为CSS模块、Tailwind等方案。
扩展优化方向
- 添加返回按钮,快速回到分类列表
- 替换加载状态为骨架屏,提升用户体验
- 对过长的菜品描述做截断处理,添加展开/收起功能
- 集成真实API时,增加错误捕获和异常提示
内容的提问来源于stack exchange,提问作者Dipak
相关产品推荐
相关产品推荐

