如何实现Material-UI表格仅点击对应行时才单独展开
问题原因
你当前所有行共用了同一个open布尔状态,只要这个状态变更,所有行的展开/收起状态都会同步变更,才会出现点第一行第二行也跟着展开的问题。
修复方案
把单一的布尔状态改为存储当前展开行的唯一标识(如果要支持同时展开多行可以用数组存储多个标识),点击时仅更新对应行的标识匹配状态即可。
步骤1:修改状态定义
如果你的每条数据有唯一id字段推荐用id,没有的话可以临时用数组索引:
// 单选展开(一次只能展开一行) const [openRowId, setOpenRowId] = useState(null); // 如果要支持同时展开多行,用数组存 // const [openRowIds, setOpenRowIds] = useState([]);
步骤2:修改点击事件和展开判断
同时修正你原代码里data遍历的语法错误,原代码写的data((index) =>)应为data.map((item, index) =>):
<Table stickyHeader aria-label="sticky table"> <TableHead> <TableRow hover> <TableCell>Title</TableCell> <TableCell>Created Date</TableCell> </TableRow> </TableHead> <TableBody> {data && data.map((item, index) => ( <TableRow hover key={item.id || index}> {/* 必须加唯一key */} <TableCell> <IconButton aria-label="expand row" size="small" onClick={() => { // 单选展开逻辑 setOpenRowId(openRowId === (item.id || index) ? null : (item.id || index)) // 多选展开逻辑 /* setOpenRowIds(prev => { const id = item.id || index return prev.includes(id) ? prev.filter(v => v !== id) : [...prev, id] }) */ }} > {/* 单选判断 */} {openRowId === (item.id || index) ? ( <KeyboardArrowUpIcon /> ) : ( <KeyboardArrowDownIcon /> )} {/* 多选判断 */} {/* {openRowIds.includes(item.id || index) ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} */} </IconButton> </TableCell> <TableCell component="th" scope="row"> {item.title} </TableCell> <TableCell component="th" scope="row"> {new Date( item.createdDate.seconds * 1000 ).toDateString()} </TableCell> <TableCell colSpan={6}> {/* 单选in属性 */} <Collapse in={openRowId === (item.id || index)} timeout="auto" unmountOnExit> {item.text} </Collapse> {/* 多选in属性 */} {/* <Collapse in={openRowIds.includes(item.id || index)} timeout="auto" unmountOnExit> {item.text} </Collapse> */} </TableCell> </TableRow> ))} </TableBody> </Table>
注意事项
- 遍历渲染TableRow时必须加唯一
key属性,否则React渲染列表时也可能出现状态串位的问题 - 优先用数据本身的唯一id作为标识,不要默认用数组索引,如果你有列表排序、删除、新增的需求,用索引会导致标识对应错误
内容的提问来源于stack exchange,提问作者JS3
相关产品推荐
相关产品推荐

