React表格行同步折叠问题:如何实现点击行单独折叠展开?
解决方案
问题根源在于你用了一个全局布尔值open控制所有行的折叠状态,所有行共享同一状态,所以点击任意一行都会同步切换所有行的展开/折叠。要实现单独控制每一行,需要为每个行维护独立的展开状态,具体修改步骤如下:
1. 修改状态定义
把单个布尔值状态改成数组,用来存储所有处于展开状态的行的唯一标识(优先用行的id,如果没有则用city,确保标识唯一):
// 用数组存储展开行的唯一标识,初始为空数组 const [expandedRows, setExpandedRows] = useState([]);
2. 修改点击事件逻辑
点击图标时,切换当前行的展开状态(已展开就从数组移除,未展开则添加到数组):
<IconButton aria-label="expand row" size="small" onClick={() => { setExpandedRows(prevState => prevState.includes(row.city) ? prevState.filter(item => item !== row.city) // 已展开则移除 : [...prevState, row.city] // 未展开则添加 ); }} >
3. 更新折叠组件和图标判断
将Collapse的in属性和图标显示逻辑,从全局open改成判断当前行的标识是否在expandedRows数组中:
// 图标切换逻辑 {expandedRows.includes(row.city) ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} // Collapse组件的展开条件 <Collapse in={expandedRows.includes(row.city)} timeout="auto" unmountOnExit>
修改后的完整代码片段
const [expandedRows, setExpandedRows] = useState([]); // ...其他代码 <TableBody> {isCityReady && cities ? (cities.map((row, index) => ( <TableRow key={index} sx={{ borderBottom: "2px solid black", "&:last-child td, &:last-child th": { border: 0 } }}> <TableCell> <IconButton aria-label="expand row" size="small" onClick={() => { setExpandedRows(prevState => prevState.includes(row.city) ? prevState.filter(item => item !== row.city) : [...prevState, row.city] ); }} > {expandedRows.includes(row.city) ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} </IconButton> </TableCell> <TableCell component="th" scope="row" align="left"> <Typography variant="body1" fontWeight="bold"> {row.city} </Typography> </TableCell> <TableCell> <Collapse in={expandedRows.includes(row.city)} timeout="auto" unmountOnExit> <Typography variant="body1" fontWeight="bold"> {isReady && locations ? (locations.filter(rowLocation => rowLocation.city === row.city).map((rowLocation, indexLocation) => ( <TableRow key={indexLocation} sx={{ "&:last-child td, &:last-child th": { border: 0 } }}> <TableCell style={{ width: '100%' }}> <Typography variant="body1"> {rowLocation.office} </Typography> </TableCell> <TableCell align="right" style={{ width: '100%' }}> <Button variant="contained" color="primary" onClick={() => handleOpenLocationsDialog("Edit", rowLocation.city, rowLocation.office, rowLocation.id)}> Edit </Button> </TableCell> </TableRow> ))) : (<LocationsTableSkeleton />)} </Typography> </Collapse> </TableCell> </TableRow> )) ) : ( <LocationsTableSkeleton /> )}
额外优化建议
如果你的row对象有唯一的id字段,建议用row.id代替row.city作为标识,避免出现多个行城市名称相同导致状态混乱的情况。
内容的提问来源于stack exchange,提问作者PaulPolon
相关产品推荐
相关产品推荐

