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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 13:17:04