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

Material-UI v1:MenuItem点击时如何传递外层map的folder对象?

解决Table中MenuItem点击传递错误folder对象的问题

嗨,我来帮你搞定这个问题!你遇到的是闭包经典陷阱,再加上一个小语法错误,咱们一步步解决:

首先纠正明显的语法错误

你第二个MenuItem的onClick写成了{{event => onDeleteFolder(event, folder)}}——这里多了一层大括号,变成传递对象而不是函数了,先改成箭头函数的正确写法:

<MenuItem onClick={(event) => onDeleteFolder(event, folder)}>

解决闭包导致的变量共享问题

在folders.map循环里直接写onClick={(event) => onEditFolder(event, folder)},会因为闭包特性让所有函数都引用同一个folder变量,循环结束后这个变量指向最后一个元素,所以点击时总是拿到最后一个folder。

方法1:在循环内创建独立的处理函数

在map的每次迭代里,把当前folder绑定到单独的函数里,这样每个函数都持有自己的folder引用:

{folders.map(folder => {
  // 为当前folder创建专属的处理函数
  const handleEdit = (event) => onEditFolder(event, folder);
  const handleDelete = (event) => onDeleteFolder(event, folder);

  return (
    <TableRow key={folder.id}>
      <TableCell>{folder.name}</TableCell>
      <TableCell>
        <IconButton onClick={(e) => this.handleFolderActionClick(e, folder.id)}>
          <MoreHoriz />
        </IconButton>
        <Menu 
          open={this.state.menuOpen[folder.id] || false}
          anchorEl={this.state.anchorEls[folder.id]}
          onClose={() => this.handleFolderActionClose(folder.id)}
        >
          <MenuItem onClick={handleEdit}>
            <ListItemIcon><Edit /></ListItemIcon>
            <ListItemText inset primary="Edit" />
          </MenuItem>
          <MenuItem onClick={handleDelete}>
            <ListItemIcon><Delete /></ListItemIcon>
            <ListItemText inset primary="Delete" />
          </MenuItem>
        </Menu>
      </TableCell>
    </TableRow>
  );
})}

对应的类组件状态和方法要调整为支持多菜单:

state = {
  menuOpen: {},
  anchorEls: {}
};

handleFolderActionClick = (event, folderId) => {
  this.setState({
    anchorEls: { ...this.state.anchorEls, [folderId]: event.currentTarget },
    menuOpen: { ...this.state.menuOpen, [folderId]: true }
  });
};

handleFolderActionClose = (folderId) => {
  this.setState({
    menuOpen: { ...this.state.menuOpen, [folderId]: false }
  });
};

方法2:将行内容抽成独立子组件

把每个TableRow的内容拆成单独的组件,这样每个子组件会接收自己的folder prop,完全避免闭包问题,代码也更清晰:

// 子组件
const FolderRow = ({ folder, onEditFolder, onDeleteFolder }) => {
  const [anchorEl, setAnchorEl] = useState(null);
  const open = Boolean(anchorEl);

  const handleClick = (event) => setAnchorEl(event.currentTarget);
  const handleClose = () => setAnchorEl(null);

  return (
    <TableRow key={folder.id}>
      <TableCell>{folder.name}</TableCell>
      <TableCell>
        <IconButton onClick={handleClick}>
          <MoreHoriz />
        </IconButton>
        <Menu open={open} anchorEl={anchorEl} onClose={handleClose}>
          <MenuItem onClick={(e) => {
            onEditFolder(e, folder);
            handleClose();
          }}>
            <ListItemIcon><Edit /></ListItemIcon>
            <ListItemText inset primary="Edit" />
          </MenuItem>
          <MenuItem onClick={(e) => {
            onDeleteFolder(e, folder);
            handleClose();
          }}>
            <ListItemIcon><Delete /></ListItemIcon>
            <ListItemText inset primary="Delete" />
          </MenuItem>
        </Menu>
      </TableCell>
    </TableRow>
  );
};

// 父组件中使用
{folders.map(folder => (
  <FolderRow 
    key={folder.id} 
    folder={folder} 
    onEditFolder={onEditFolder} 
    onDeleteFolder={onDeleteFolder} 
  />
))}

额外说明:Menu状态独立的重要性

你原来的代码里所有行的Menu共用同一个状态,点击任何一个按钮都会触发所有Menu的显示/隐藏,还会加剧变量引用的混乱。上面两种方法都处理了这个问题,让每个Menu拥有自己的独立状态,不会互相干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:45:55