如何在可折叠表格中遍历渲染API返回数据并实现单行独立展开展示详情
问题解决方案
核心修改点
- 移除全局的open状态,改用存储当前展开行唯一标识的状态,实现每行独立控制展开收起
- 渲染详情区域时直接使用map循环中当前的
detail对象,即可绑定对应行的全量数据
两种实现方案
方案1:每次仅允许展开一行(常用场景)
import { useState, useEffect, Fragment } from 'react'; import Axios from 'axios'; import { Table, TableHead, TableRow, TableCell, TableBody, IconButton, Collapse, Box, Typography, Tooltip } from '@mui/material'; import { KeyboardArrowUpIcon, KeyboardArrowDownIcon } from '@mui/icons-material'; import Wrapper from '你的Wrapper组件路径'; function Encounter() { // 存储当前展开行的唯一标识,null表示无展开行 const [openRowId, setOpenRowId] = useState(null); const [details, setDetails] = useState([]); const getDetails = async () => { try { const res = await Axios.get( "https://pshs3.herokuapp.com/all/encounter" ); setDetails(res.data.data) } catch (err) { console.log(err); } }; useEffect(() => { getDetails(); }, []); return ( <Wrapper> <Table stickyHeader aria-label="sticky table"> <TableHead> <TableRow> <TableCell/> <TableCell> Enrollment ID </TableCell> <TableCell> Encounter </TableCell> <TableCell> Facility Code </TableCell> </TableRow> </TableHead> <TableBody> {details.map((detail, idx) => { // 判断当前行是否展开:有业务唯一id(比如enrollment_id)建议替换为detail.enrollment_id const isOpen = openRowId === idx; return ( // 给循环根元素加key <Fragment key={idx}> <TableRow sx={{ "& > *": { borderBottom: "unset" } }}> <TableCell> <IconButton aria-label="expand row" size="small" onClick={() => setOpenRowId(isOpen ? null : idx)} > {isOpen ? ( <KeyboardArrowUpIcon /> ) : ( <KeyboardArrowDownIcon /> )} </IconButton> </TableCell> <TableCell> {detail.enrollment_id} </TableCell> <TableCell> {detail.encounter} </TableCell> <TableCell> {/* 修正拼写错误 faciity -> facility,可根据实际API返回调整 */} {detail.facility_code || detail.faciity_code} </TableCell> </TableRow> <TableRow> <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={4} > <Collapse in={isOpen} timeout="auto" unmountOnExit> <Box sx={{ margin: 1 }}> <Typography variant="h6" gutterBottom component="div"> Details </Typography> {/* 直接使用当前循环的detail对象渲染全量数据 */} <Tooltip title="该行完整数据"> <Box> {Object.entries(detail).map(([field, value]) => ( <Typography key={field} variant="body2" sx={{ py: 0.5 }}> <b>{field}:</b> {String(value)} </Typography> ))} </Box> </Tooltip> </Box> </Collapse> </TableCell> </TableRow> </Fragment> ); })} </TableBody> </Table> </Wrapper> ); } export default Encounter;
方案2:允许多行同时展开
如果需要支持同时展开多行,仅需要修改状态逻辑即可:
- 替换状态定义为:
// 存储所有已展开行的标识数组 const [openRowIds, setOpenRowIds] = useState([]);
- 替换行展开判断和点击逻辑:
const isOpen = openRowIds.includes(idx); const toggleRow = () => { setOpenRowIds(prev => isOpen ? prev.filter(id => id !== idx) : [...prev, idx] ) } // IconButton的onClick改为调用toggleRow onClick={toggleRow}
注意事项
- 建议优先使用业务唯一字段(如
enrollment_id)代替索引idx作为行唯一标识,避免数组排序/增删后状态对应错误 - 原代码中
faciity_code大概率是拼写错误,可根据实际API返回字段调整
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

