如何在Material UI DataGrid组件的最后一列添加Menu组件?
问题核心原因
- 所有行的Menu共用同一个布尔状态
menuOpen,点击任意行按钮会触发所有行的Menu同时尝试渲染,冲突导致无法正常显示 - MUI的Menu组件强制要求绑定
anchorEl属性来指定弹出位置,缺少该属性就算状态正确也无法正常渲染 - 直接对原
columns数组执行push操作,会修改原数组,可能导致重复添加操作列的异常
修复方案
将原来的布尔状态替换为存储当前触发菜单的锚元素和对应行ID,确保同一时间只有对应行的菜单渲染:
// 替换原有menuOpen相关状态 const [anchorEl, setAnchorEl] = useState(null); const [activeRowId, setActiveRowId] = useState(null); const getNewCells = () => { // 展开原数组避免修改原数据 const newCols = [...columns]; newCols.push({ field: 'action', flex: 1, sortable: false, filterable: false, renderCell: (cell) => { // 仅当前行菜单匹配时设置为打开状态 const isMenuOpen = Boolean(anchorEl) && activeRowId === cell.id; return ( <> <Box aria-controls={isMenuOpen ? `menu-${cell.id}` : undefined} aria-haspopup="true" aria-expanded={isMenuOpen ? 'true' : undefined} onClick={(e) => { setAnchorEl(e.currentTarget); setActiveRowId(cell.id); }} size="small" component={Button} width="2rem!important" height="2rem!important" minWidth="2rem!important" minHeight="2rem!important" > <Box component={MoreVert} width="1.25rem!important" height="1.25rem!important" position="relative" top="2px" color={theme.palette.gray[500]} /> </Box> <Menu id={`menu-${cell.id}`} open={isMenuOpen} anchorEl={anchorEl} onClose={() => { setAnchorEl(null); setActiveRowId(null); }} anchorOrigin={{ vertical: 'bottom', horizontal: 'center', }} transformOrigin={{ vertical: 'top', horizontal: 'center', }} > <MenuItem onClick={() => { goToDetail(cell.id); setAnchorEl(null); setActiveRowId(null); }}>详情</MenuItem> <MenuItem onClick={() => { // 自定义业务逻辑 setAnchorEl(null); setActiveRowId(null); }}>跳转至其他页面</MenuItem> <MenuItem onClick={() => { // 自定义业务逻辑 setAnchorEl(null); setActiveRowId(null); }}>删除</MenuItem> </Menu> </> ); }, }); return newCols; };
关键修改说明
- 用
anchorEl存储触发菜单的按钮DOM元素,给Menu组件绑定该属性,保证菜单弹出位置正确 - 新增
activeRowId存储当前打开菜单的行ID,确保同一时间只有一个行的菜单处于打开状态 - 每个菜单的ID和行ID绑定,避免DOM ID重复冲突
- 操作列设置
sortable和filterable为false,避免操作列出现排序/筛选按钮影响显示
内容的提问来源于stack exchange,提问作者Nicolas Simmonds
相关产品推荐
相关产品推荐

