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

如何通过数组渲染MUI Accordion组件并仅展示一次公共标题

解决方案

问题根因

  • 你将公共的「Quote Summary」标题、外层卡片、关闭按钮放在了循环渲染的子组件内,每生成一个Accordion就会重复渲染一次公共头部
  • 传递props时错误直接读取数组类型的Subcontents下的属性,导致副标题内容为空

实现方案

1. 调整父组件结构

将公共头部抽离到父组件,循环时仅传递每条Accordion的完整数据:

const Sandbox = () => {
  // 建议先定义好类型替代any,避免后续类型错误
  interface Subcontent {
    Subtitle: string;
    SubtitlePrice: string;
  }
  interface SummaryItem {
    Title: string;
    TotalPrice: string;
    Subcontents: Subcontent[];
  }

  const summaryContents: SummaryItem[] = [
    {
      Title: "Construction costs",
      TotalPrice: "$25000",
      Subcontents: [
        {
          Subtitle: "Sanitation",
          SubtitlePrice: "$5000",
        },
        {
          Subtitle: "PoolLights",
          SubtitlePrice: "$5000",
        },
        {
          Subtitle: "PoolCleaner",
          SubtitlePrice: "$15000",
        },
      ],
    },
    {
      Title: "Pool interior costs",
      TotalPrice: "$20000",
      Subcontents: [
        {
          Subtitle: "Title1",
          SubtitlePrice: "$5000",
        },
        {
          Subtitle: "Title2",
          SubtitlePrice: "$10000",
        },
        {
          Subtitle: "Title3",
          SubtitlePrice: "$5000",
        },
      ],
    },
  ];

  return (
    <QuoteCard>
      {/* 公共头部只渲染一次 */}
      <Typography variant="h1" sx={{ paddingBottom: 2 }}>
        Quote Summary
      </Typography>
      <DialogCloseButton onClose={clicked} />

      {/* 循环渲染单个Accordion子组件 */}
      {summaryContents.map((item, index) => (
        <QuoteSummary 
          key={index}
          panelIndex={index}
          title={item.Title}
          totalPrice={item.TotalPrice}
          subcontents={item.Subcontents}
        />
      ))}
    </QuoteCard>
  );
};

2. 调整子组件只负责单个Accordion渲染

子组件内删除公共头部逻辑,新增数组循环渲染副标题内容,同时给Accordion绑定唯一id避免展开冲突:

// 先定义子组件props类型
interface QuoteSummaryProps {
  panelIndex: number;
  title: string;
  totalPrice: string;
  subcontents: Array<{
    Subtitle: string;
    SubtitlePrice: string;
  }>
}

const QuoteSummary: FC<QuoteSummaryProps> = (props) => {
  const classes = useStyles();
  return (
    <Accordion
      className={classes.accordion}
      sx={{ paddingTop: 0 }}
    >
      <AccordionSummary
        expandIcon={<ExpandMoreIcon />}
        aria-controls={`panel${props.panelIndex}a-content`}
        id={`panel${props.panelIndex}a-header`}
      >
        <Typography variant="h3">{props.title}</Typography>
        <Typography variant="h3" sx={{ paddingLeft: 10 }}>
          {props.totalPrice}
        </Typography>
      </AccordionSummary>
      <AccordionDetails>
        {/* 循环渲染所有副标题条目 */}
        {props.subcontents.map((subItem, subIndex) => (
          <div key={subIndex} style={{ display: 'flex', gap: '10px' }}>
            <Typography>{subItem.Subtitle}</Typography>
            <Typography>{subItem.SubtitlePrice}</Typography>
          </div>
        ))}
      </AccordionDetails>
    </Accordion>
  );
};

注意事项

  • 用map替代forEachpush数组是React渲染列表的标准写法,更简洁易维护
  • 所有循环渲染的列表项都需要绑定唯一key属性,避免渲染异常
  • 多个Accordion面板的id、aria属性需要和索引绑定,否则点击一个面板会触发所有面板同时展开/收起

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

相关产品推荐
方舟 Agent Plan

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

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