如何在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
相关产品推荐
相关产品推荐

