MUI MenuItem传参异常:点击菜单始终传递最后元素props
问题原因
你遇到的问题根源有两个:
- 所有列表项共享同一个
anchorEl状态变量,点击任意按钮都会更新这个全局状态,导致所有菜单都绑定到最后点击的元素,且判断是否显示的open状态也是全局的。 - 闭包陷阱:
onClick回调里的lyrKey会捕获循环最后一次迭代的值,所以不管点哪个菜单,最终传入的都是最后一个元素的lyrKey。
解决方案
把菜单的状态按每个列表项独立管理,用对象存储每个lyrKey对应的锚点元素,同时确保回调里的lyrKey能正确绑定当前项的值。
修改后的完整代码如下:
const TOC = (props) => { const dispatch = useDispatch(); // 用对象存储每个图层对应的锚点元素,key是lyrKey const [anchorEls, setAnchorEls] = React.useState({}); const map = useSelector((state) => state.app.mapContext); const layers = useSelector((state) => state.app.layers); // 针对特定lyrKey处理点击,存储对应的锚点 const handleClick = (event, lyrKey) => { setAnchorEls(prev => ({ ...prev, [lyrKey]: event.currentTarget })); }; // 关闭特定lyrKey的菜单 const handleClose = (lyrKey) => { setAnchorEls(prev => ({ ...prev, [lyrKey]: null })); }; const options = [ { component: <ZoomInIcon />, key: "zoomIcon", cb: (lyrKey) => handleZoomClick(layers[lyrKey].vectorLayer), text: "Zoom", }, { component: <DriveFileRenameOutlineIcon />, key: "renameLayer", cb: (lyrKey) => { console.log(lyrKey); dispatch( setDialog({ open: true, title: `Change ${lyrKey} Layer name`, child: <Rename old_name={lyrKey} />, }) ); }, text: "Rename", }, ]; return ( <> {Object.keys(layers).map((lyrKey) => { // 当前图层对应的菜单是否打开 const isOpen = Boolean(anchorEls[lyrKey]); return ( <div className="toc__element" key={lyrKey}> <label> <input type="checkbox" name={lyrKey} checked={layers[lyrKey]?.show || false} onChange={handleChange} /> {lyrKey} </label> {/* 点击时传入当前lyrKey */} <MoreVertIcon onClick={(e) => handleClick(e, lyrKey)} /> <Menu id={`lock-menu-${lyrKey}`} {/* 每个菜单用唯一ID */} anchorEl={anchorEls[lyrKey]} open={isOpen} onClose={() => handleClose(lyrKey)} > {options.map((option) => ( <MenuItem key={`${option.key}-${lyrKey}`} onClick={(e) => { console.log(lyrKey); handleClose(lyrKey); option.cb(lyrKey); }} > {option.text} {option.component} </MenuItem> ))} </Menu> </div> ); })} </> ); };
关键修改点
- 状态独立:将单个
anchorEl改为anchorEls对象,每个lyrKey对应自己的锚点元素,避免全局状态冲突。 - 绑定当前lyrKey:
handleClick接收当前lyrKey,确保点击时存储的是对应项的锚点;菜单的open状态只依赖当前lyrKey对应的锚点。 - 唯一ID:每个菜单的
id加上lyrKey后缀,避免DOM元素ID重复。 - 闭包问题解决:在
map的每次迭代中,lyrKey作为参数传入回调,确保每个菜单的onClick能捕获到当前项的正确值。
内容的提问来源于stack exchange,提问作者Ahmed Gaafer
相关产品推荐
相关产品推荐

