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

React中嵌套map渲染菜单并过滤重复项的实现问题咨询

问题核心原因

你现在的写法存在3个共性错误,导致无法正常渲染:

  • 没有显式返回JSX元素:map回调中编写的<Typography>组件没有加return,React无法识别这些元素
  • 缺少父容器包裹:React不允许同一个回调返回多个无父节点的同级元素,需要用Fragment或容器组件包裹
  • 匹配逻辑不合理:直接在map中做if判断会生成大量undefined空项,同时每次嵌套都遍历全量子数组,容易出现重复匹配、逻辑混乱的问题

实现方案

推荐先把接口返回的扁平数据转成嵌套结构,再做渲染,逻辑更清晰,后续维护也更方便:

步骤1:结构化处理数据

const nestedMenu = LocationMenuStore.menuItems.menu.headings.map(heading => {
  // 匹配当前一级标题对应的所有二级标题
  const relatedSubHeadings = LocationMenuStore.menuItems.menu.sub_headings
    .filter(sub => sub.menu_heading_id === heading.id)
    .map(subHeading => {
      // 匹配当前二级标题对应的所有菜单项
      const relatedItems = LocationMenuStore.menuItems.menu.items.filter(
        item => item.sub_heading_id === subHeading.id
      )
      return { ...subHeading, items: relatedItems }
    })
  return { ...heading, subHeadings: relatedSubHeadings }
})

步骤2:嵌套渲染菜单

const fullMenu = nestedMenu.map(heading => (
  <React.Fragment key={heading.id}>
    {/* 一级标题 */}
    <Typography>{heading.heading_name}</Typography>
    {/* 渲染二级标题 */}
    {heading.subHeadings.map(subHeading => (
      <React.Fragment key={subHeading.id}>
        <Typography style={{ paddingLeft: '16px' }}>{subHeading.sub_heading_name}</Typography>
        {/* 渲染菜单项 */}
        {subHeading.items.map(item => (
          <Typography key={item.id} style={{ paddingLeft: '32px' }}>{item.item_name}</Typography>
        ))}
      </React.Fragment>
    ))}
  </React.Fragment>
))

如果不想提前处理数据,也可以直接在渲染时做filter+map,效果一致:

const fullMenu = LocationMenuStore.menuItems.menu.headings.map(heading => (
  <React.Fragment key={heading.id}>
    <Typography>{heading.heading_name}</Typography>
    {LocationMenuStore.menuItems.menu.sub_headings
      .filter(sub => sub.menu_heading_id === heading.id)
      .map(subHeading => (
        <React.Fragment key={subHeading.id}>
          <Typography style={{ paddingLeft: '16px' }}>{subHeading.sub_heading_name}</Typography>
          {LocationMenuStore.menuItems.menu.items
            .filter(item => item.sub_heading_id === subHeading.id)
            .map(item => (
              <Typography key={item.id} style={{ paddingLeft: '32px' }}>{item.item_name}</Typography>
            ))
          }
        </React.Fragment>
      ))
    }
  </React.Fragment>
))

代码中的paddingLeft仅为了体现层级缩进,你可以根据实际UI需求替换为自定义类名或其他样式规则,key属性必须添加,可避免React渲染警告和重复渲染问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 16:24:02