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

如何在可折叠表格中遍历渲染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:允许多行同时展开

如果需要支持同时展开多行,仅需要修改状态逻辑即可:

  1. 替换状态定义为:
// 存储所有已展开行的标识数组
const [openRowIds, setOpenRowIds] = useState([]);
  1. 替换行展开判断和点击逻辑:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 11:09:03