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

如何在React函数式组件中为多个MUI Collapse设置动态状态

存在的问题

  • 所有折叠面板共用同一个open布尔状态:全局只定义了一个[open, setOpen],任意一个折叠项点击都会修改这个全局状态,导致所有面板同步展开/收起,无法独立控制。
  • List组件的aria-labelledby和ListSubheader的id属性存在语法错误:你写的'{item.listCities.id}'处于map循环外部,此时item变量不存在,且不需要给JSX表达式套单引号。
  • 数组直接作为组件属性值:item.listCities.names是数组,直接传给ListItemText的primary属性会导致React渲染报错。
  • 缺少Box组件的导入声明。

修复方案

将状态修改为存储当前展开的面板ID,点击时传入对应ID做匹配判断,即可实现独立控制。如果需要支持同时展开多个面板,可将状态改为对象类型存储每个ID的展开状态。

单展开模式(同一时间只能展开一个面板)修正后代码

import React from 'react';
import Box from '@mui/material/Box';
import ListSubheader from '@mui/material/ListSubheader';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import Collapse from '@mui/material/Collapse';
import ExpandLess from '@mui/icons-material/ExpandLess';
import ExpandMore from '@mui/icons-material/ExpandMore';

const MyClass = ({data}) => {
  // 状态存储当前展开的面板ID,null代表无展开项
  const [openId, setOpenId] = React.useState(null)

  // 点击时传入当前项的ID做判断
  const handleClick = (id) =>{
    setOpenId(openId === id ? null : id)
  };

  return (
    <List
      sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
      component="nav"
      aria-labelledby="nested-list-subheader"
      subheader={
        <ListSubheader component="div" id="nested-list-subheader">
          Lists
        </ListSubheader>
      }
    >
      {
        data.map(item => {
          const currentId = item.listCities.id;
          const isOpen = openId === currentId;
          return (
            <Box component="section" key={currentId}>
              <ListItemButton onClick={() => handleClick(currentId)}>
                <ListItemText primary={item.listCities.city} />
                {isOpen ? <ExpandLess /> : <ExpandMore />}
              </ListItemButton>
              <Collapse in={isOpen} timeout="auto" unmountOnExit>
                <List component="div" disablePadding>
                  {/* 遍历names数组渲染子项 */}
                  {item.listCities.names.map((name, index) => (
                    <ListItemButton sx={{ pl: 4 }} key={index}>
                      <ListItemText primary={name} />
                    </ListItemButton>
                  ))}
                </List>
              </Collapse>
            </Box>
          )
        })
      }
    </List>
  )   
}

多展开模式(可同时展开多个面板)修改逻辑

如果需要支持同时展开多个面板,只需替换状态定义和点击逻辑即可:

// 状态改为对象存储每个ID的展开状态
const [openMap, setOpenMap] = React.useState({})
const handleClick = (id) =>{
  setOpenMap(prev => ({
    ...prev,
    [id]: !prev[id]
  }))
};
// 对应展开判断逻辑改为
const isOpen = !!openMap[currentId]

原有组件调用代码无需修改即可正常运行。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 22:39:01