MUI受控Accordion两组列表同步联动问题求助
同步联动MUI Accordion的问题排查与修复
问题描述
拥有两组MUI Accordion列表,期望实现二者同步联动:展开左侧的Accordion 1时,右侧对应的Accordion 1同步展开,反之亦然。已通过状态维护Accordion的默认展开状态,但联动功能失效。
问题根源
handleChange函数中更新状态时直接引用了当前的expanded变量,由于React的闭包特性,这里获取到的是组件渲染时的旧状态值,无法正确反映最新状态,导致状态更新不精准,最终两组Accordion无法同步。
修复方案
将setExpanded的更新逻辑改为函数式更新,利用函数参数获取最新的状态值,确保每次状态更新都是基于当前最新状态进行修改:
import * as React from 'react'; import Accordion from '@mui/material/Accordion'; import AccordionDetails from '@mui/material/AccordionDetails'; import AccordionSummary from '@mui/material/AccordionSummary'; import Typography from '@mui/material/Typography'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; export default function ControlledAccordions() { const [expanded, setExpanded] = React.useState<Record<string, boolean>>({}); const arr = [1, 2, 3]; React.useEffect(() => { setExpanded( arr.reduce((a, c) => { a[`panel${c}`] = true; return a; }, {} as Record<string, boolean>) ); }, []); // 修改为函数式更新获取最新状态 const handleChange = (panel: string) => (event: React.SyntheticEvent, isExpanded: boolean) => { setExpanded(prevExpanded => ({ ...prevExpanded, [panel]: isExpanded, })); }; console.log('expanded', expanded); return ( <div style={{ display: 'flex', flexDirection: 'row', }} > <div> {arr.map((i) => ( <Accordion key={`left-panel${i}`} expanded={expanded[`panel${i}`]} onChange={handleChange(`panel${i}`)} > <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls={`left-panel${i}-content`} id={`leftpanel${i}bh-header`} > <Typography sx={{ width: '33%', flexShrink: 0 }}> General settings </Typography> <Typography sx={{ color: 'text.secondary' }}> I am an accordion </Typography> </AccordionSummary> <AccordionDetails> <Typography> Nulla facilisi. Phasellus sollicitudin nulla et quam mattis feugiat. Aliquam eget maximus est, id dignissim quam. </Typography> </AccordionDetails> </Accordion> ))} </div> <div> {arr.map((i) => ( <Accordion key={`right-panel${i}`} expanded={expanded[`panel${i}`]} onChange={handleChange(`panel${i}`)} > <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls={`right-panel${i}-content`} id={`rightpanel${i}bh-header`} > <Typography sx={{ width: '33%', flexShrink: 0 }}> General settings </Typography> <Typography sx={{ color: 'text.secondary' }}> I am an accordion </Typography> </AccordionSummary> <AccordionDetails> <Typography> Nulla facilisi. Phasellus sollicitudin nulla et quam mattis feugiat. Aliquam eget maximus est, id dignissim quam. </Typography> </AccordionDetails> </Accordion> ))} </div> </div> ); }
额外优化点:
- 为每个Accordion添加唯一的
key属性,避免React控制台警告 - 修正
aria-controls属性值,确保每个Accordion的控制元素ID唯一,符合无障碍规范
内容的提问来源于stack exchange,提问作者arunmmanoharan
相关产品推荐
相关产品推荐

