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

Material UI折叠面板动画失效求助:子组件引入无平滑过渡

Material UI Accordion封装子组件后动画失效的解决方案

问题原因

最常见的触发原因是子组件被定义在父组件的渲染函数内部,导致父组件每次重新渲染时都会创建一个全新的AccordionItem组件类型。React会将其识别为不同的组件,从而卸载旧组件并重新挂载新组件——这会丢失Accordion内部的状态和动画依赖的DOM稳定性,最终导致折叠/展开时无平滑过渡,直接突变。

另外,如果父组件控制Accordion的expanded状态时,状态管理不稳定或未给Accordion设置唯一key,也可能引发类似问题。

解决方案

1. 将子组件移到父组件外部定义

不要在函数组件的内部(即App函数里)定义子组件,而是把AccordionItem放在父组件外部或单独的文件中:

// 正确:子组件定义在父组件外部
import { Accordion, AccordionDetails, AccordionSummary, Typography } from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";

const AccordionItem = () => {
  return (
    <Accordion>
      <AccordionSummary expandIcon={<ExpandMoreIcon />}>
        <Typography>Accordion 1</Typography>
      </AccordionSummary>
      <AccordionDetails>
        <Typography>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
        </Typography>
      </AccordionDetails>
    </Accordion>
  );
};

export default function App() {
  return (
    <div className="App">
      <AccordionItem />
    </div>
  );
}

2. 若需依赖父组件props,用useMemo缓存组件

如果子组件必须依赖父组件的props才能定义,可以用React.useMemo缓存组件,避免每次渲染都重新创建:

import React from "react";
import { Accordion, AccordionDetails, AccordionSummary, Typography } from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";

export default function App({ panelTitle }) {
  // 用useMemo缓存组件,仅当依赖项变化时才重新创建
  const AccordionItem = React.useMemo(() => {
    return () => (
      <Accordion>
        <AccordionSummary expandIcon={<ExpandMoreIcon />}>
          <Typography>{panelTitle}</Typography>
        </AccordionSummary>
        <AccordionDetails>
          <Typography>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
          </Typography>
        </AccordionDetails>
      </Accordion>
    );
  }, [panelTitle]);

  return <AccordionItem />;
}

3. 受控模式下确保状态稳定并设置唯一key

如果使用父组件控制Accordion的展开状态,要保证状态逻辑稳定,同时给Accordion设置唯一的key属性,避免不必要的组件重新挂载:

import React, { useState } from "react";
import { Accordion, AccordionDetails, AccordionSummary, Typography } from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";

const AccordionItem = ({ expanded, onChange, title }) => {
  return (
    <Accordion 
      expanded={expanded} 
      onChange={onChange}
      key={title} // 设置唯一key
    >
      <AccordionSummary expandIcon={<ExpandMoreIcon />}>
        <Typography>{title}</Typography>
      </AccordionSummary>
      <AccordionDetails>
        <Typography>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
        </Typography>
      </AccordionDetails>
    </Accordion>
  );
};

export default function App() {
  const [expandedPanel, setExpandedPanel] = useState<string | false>(false);

  const handlePanelChange = (panelId: string) => (_, isExpanded) => {
    setExpandedPanel(isExpanded ? panelId : false);
  };

  return (
    <div className="App">
      <AccordionItem
        title="Accordion 1"
        expanded={expandedPanel === "panel1"}
        onChange={handlePanelChange("panel1")}
      />
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 05:15:21