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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 14:37:15