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

React表格菜单按钮异常:所有行均显示最后一行数据

React表格菜单显示最后一行信息的解决方案

问题核心是所有行共用了同一个状态和重复的DOM标识:

  • 全局open布尔值和anchorEl变量被所有菜单绑定,点击任意按钮都会触发同一个状态,而循环结束后row.videoId会保留最后一行的值,导致菜单显示最后一行数据
  • 按钮和菜单的ID(long-button、long-menu)固定重复,浏览器无法区分不同行的菜单组件

解决思路

  1. 将全局open状态改为存储当前激活的videoId(初始为null),精准控制单一行菜单的显示
  2. 给每一行的按钮和菜单设置唯一ID,用row.videoId作为标识后缀
  3. 修改菜单触发逻辑,绑定当前行的videoId

修改后的代码示例

// 组件内状态定义修改
const [selectedVideoId, setSelectedVideoId] = useState(null);
const [anchorEl, setAnchorEl] = useState(null);

// 菜单点击处理函数,接收当前行的videoId和事件对象
const handleOptionsClick = (event, videoId) => {
  setAnchorEl(event.currentTarget);
  setSelectedVideoId(videoId);
};

// 菜单关闭函数
const handleClose = () => {
  setAnchorEl(null);
  setSelectedVideoId(null);
};

// 表格主体代码修改
<TableBody>
  {visibleRows.map((row, index) => {
    const videoId = row.videoId;
    const isItemSelected = isSelected(row.videoId.toString());
    const labelId = `enhanced-table-checkbox-${index}-${row.videoId}`;
    // 生成当前行按钮和菜单的唯一ID
    const buttonId = `long-button-${videoId}`;
    const menuId = `long-menu-${videoId}`;

    return (
      <TableRow
        key={row.videoId as string}
        hover
        onClick={(event) => handleClick(event, row.videoId.toString())}
        role="checkbox"
        tabIndex={-1}
        sx={{ cursor: 'pointer' }}
      >
        <TableCell
          align="left"
          sx={{
            maxWidth: 154,
            whiteSpace: 'nowrap',
            overflow: 'hidden',
            textOverflow: 'ellipsis',
          }}
        >
          {row.videoId}
          <IconButton
            aria-label="more"
            id={buttonId}
            aria-controls={selectedVideoId === videoId ? menuId : undefined}
            aria-expanded={selectedVideoId === videoId ? 'true' : undefined}
            aria-haspopup="true"
            onClick={(e) => handleOptionsClick(e, videoId)}
          >
            <MoreVertIcon />
          </IconButton>
          <Menu
            id={menuId}
            MenuListProps={{
              'aria-labelledby': buttonId,
            }}
            anchorEl={anchorEl}
            open={selectedVideoId === videoId}
            onClose={handleClose}
            PaperProps={{
              style: {
                maxHeight: ITEM_HEIGHT * 4.5,
                width: '20ch',
              },
            }}
          >
            <MenuItem key="edit" onClick={handleClose}>
              <a href={`https://webiste.com/${row.videoId}/edit`}>{row.videoId}</a>
            </MenuItem>
          </Menu>
        </TableCell>
      </TableRow>
    );
  })}
  {emptyRows > 0 && (
    <TableRow
      style={{
        height: 53 * emptyRows,
      }}
    >
      <TableCell colSpan={6} />
    </TableRow>
  )}
</TableBody>

关键改动说明

  • 用selectedVideoId替代原open状态,通过匹配当前行ID控制菜单显示
  • 按钮和菜单ID加入videoId后缀,保证DOM标识唯一
  • 点击按钮时传入当前行videoId,绑定激活状态
  • 菜单open条件改为判断selectedVideoId与当前行ID是否匹配

内容的提问来源于stack exchange,提问作者Exorcismus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 01:00:23