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

React中如何从Props提取API返回的JSON数据并展示菜单

解决React中API返回套餐数据展示到Tabs标签页的问题

我来帮你一步步搞定这个需求!咱们从数据处理、标签页渲染到内容切换,把每个环节都理清楚。

1. 先对齐API数据结构(假设你的返回格式类似这样)

先模拟一个符合需求的API返回JSON,方便后续代码示例参考:

{
  "mealPackages": [
    {
      "packageId": "breakfast",
      "packageName": "元气早餐套餐",
      "packageMenu": [
        { "dishId": "b1", "name": "现磨豆浆", "price": 4 },
        { "dishId": "b2", "name": "鲜肉包子", "price": 6 }
      ]
    },
    {
      "packageId": "lunch",
      "packageName": "工作日午餐套餐",
      "packageMenu": [
        { "dishId": "l1", "name": "番茄炒蛋", "price": 18 },
        { "dishId": "l2", "name": "杂粮米饭", "price": 3 }
      ]
    }
  ]
}

2. 完整React组件实现(含注释)

下面是可直接复用的组件示例,包含API请求、Tabs渲染和内容切换逻辑:

import { useState, useEffect } from 'react';

const PackageMenuTabs = () => {
  // 存储API返回的套餐数据
  const [packageList, setPackageList] = useState([]);
  // 记录当前选中的标签索引
  const [activeTab, setActiveTab] = useState(0);

  // 1. 组件挂载时请求API数据
  useEffect(() => {
    const fetchMealPackages = async () => {
      try {
        const res = await fetch('你的API接口地址');
        const data = await res.json();
        // 根据你实际的API结构调整,这里假设套餐数组在data.mealPackages里
        setPackageList(data.mealPackages);
      } catch (err) {
        console.error('获取套餐数据失败:', err);
      }
    };

    fetchMealPackages();
  }, []);

  // 2. 处理标签切换事件
  const handleTabClick = (index) => {
    setActiveTab(index);
  };

  // 数据未加载完成时显示加载状态
  if (packageList.length === 0) {
    return <div style={{ padding: '20px' }}>加载中...</div>;
  }

  return (
    <div style={{ maxWidth: '800px', margin: '20px auto' }}>
      {/* 标签页头部 */}
      <div style={{ display: 'flex', borderBottom: '1px solid #eee' }}>
        {packageList.map((pkg, index) => (
          <button
            key={pkg.packageId}
            style={{
              padding: '10px 20px',
              border: 'none',
              background: activeTab === index ? '#f5f5f5' : 'transparent',
              cursor: 'pointer',
              fontSize: '16px',
              fontWeight: activeTab === index ? 'bold' : 'normal',
              borderBottom: activeTab === index ? '2px solid #1890ff' : 'none'
            }}
            onClick={() => handleTabClick(index)}
          >
            {pkg.packageName}
          </button>
        ))}
      </div>

      {/* 当前标签对应的餐品内容 */}
      <div style={{ padding: '20px' }}>
        <h3>{packageList[activeTab].packageName} 餐品列表</h3>
        <ul style={{ listStyle: 'none', paddingLeft: 0 }}>
          {packageList[activeTab].packageMenu.map(dish => (
            <li key={dish.dishId} style={{ padding: '8px 0', borderBottom: '1px dashed #eee' }}>
              <span>*{dish.name}*</span>
              <span style={{ float: 'right', color: '#f5222d' }}>¥{dish.price}</span>
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
};

export default PackageMenuTabs;

3. 关键逻辑拆解

  • 数据获取:用useEffect在组件首次挂载时发起API请求,把返回的套餐数组存入状态packageList,注意要根据你实际的API返回结构调整赋值逻辑。
  • 标签生成:通过map遍历packageList,为每个套餐生成一个标签按钮,用套餐的packageId作为唯一key,避免React渲染警告。
  • 内容切换:用activeTab状态记录当前选中的标签索引,点击标签时更新索引,然后根据索引从packageList中取出对应套餐的packageMenu数组,遍历渲染餐品。
  • 状态提示:在数据未加载完成时显示"加载中...",避免页面出现空白或错误。

4. 适配不同UI库的小技巧

如果你用Ant Design、Material UI这类组件库,只需要把自定义的标签按钮替换成对应库的Tabs和Tab组件即可,核心逻辑完全一致:
比如Ant Design的写法:

import { Tabs } from 'antd';
const { TabPane } = Tabs;

// ... 其他逻辑不变
return (
  <Tabs activeKey={String(activeTab)} onChange={(key) => setActiveTab(Number(key))}>
    {packageList.map((pkg, index) => (
      <TabPane tab={pkg.packageName} key={String(index)}>
        {/* 餐品列表内容 */}
      </TabPane>
    ))}
  </Tabs>
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:38:50