如何通过数组渲染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
相关产品推荐
相关产品推荐

