Material-UI v1:MenuItem点击时如何传递外层map的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
相关产品推荐
相关产品推荐

