如何修复MUI中`anchorEl`属性无效及菜单定位错误问题
问题原因
- 重复渲染Menu组件:当前在DataGrid的
status列renderCell中,每一行都会渲染一个Filters的Menu,多个Menu实例共享同一个anchorElFilters状态,造成状态混乱,触发anchorEl无效的报错。 - Menu位置错误:Filters菜单嵌套在表格行的单元格里,和触发它的Toolbar按钮/文本不在同一作用域,无法正确绑定点击源的位置,导致菜单显示在左上角。
修改步骤
1. 拆分独立菜单状态
给行内操作按钮单独设置状态,避免和Toolbar的Filters菜单共享状态:
// 新增行内操作菜单的独立状态 const [anchorElRowMenu, setAnchorElRowMenu] = React.useState(null); const handleRowMenuOpen = (event) => { setAnchorElRowMenu(event.currentTarget); }; const handleRowMenuClose = () => { setAnchorElRowMenu(null); };
2. 移除行内重复的Filters Menu
修改status列的renderCell,只保留行内操作按钮,删除嵌套的Filters Menu:
const columns = [ { field: 'formName', headerName: 'Form Name', flex: 0.5 }, { field: 'associateAPIName', headerName: 'Associate API Name', flex: 0.5 }, { field: 'status', headerName: 'Status', flex: 0.2, renderCell: (params) => ( <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', minWidth: '100%' }}> {params.value} <IconButton onClick={handleRowMenuOpen}> <MoreVertIcon /> </IconButton> </div> ), }, ];
3. 将Filters/Density Menu移到Toolbar层级
在Toolbar组件内部添加对应的Menu,确保和触发按钮/文本在同一作用域,同时配置菜单的弹出位置:
components={{ Toolbar: () => ( <> <Box borderBottom={1} borderColor="rgba(224, 224, 224, 1)" pb={0}> <Toolbar> {/* Filters and Density side by side */} <div style={{ display: 'flex', alignItems: 'center' }}> <FormControl> <Tooltip title="Filters"> <IconButton onClick={handleMenuOpenFilters}> <img src={filterIcon} alt="filter-icon"/> </IconButton> </Tooltip> </FormControl> <Typography sx={{cursor: 'pointer'}} color={'#2196F3'} onClick={handleMenuOpenFilters}>FILTERS</Typography> {/* Filters菜单 */} <Menu anchorEl={anchorElFilters} open={Boolean(anchorElFilters)} onClose={handleMenuCloseFilters} anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }} transformOrigin={{ vertical: 'top', horizontal: 'left' }} > <MenuItem onClick={handleMenuCloseFilters}>Filter Option 1</MenuItem> <MenuItem onClick={handleMenuCloseFilters}>Filter Option 2</MenuItem> <MenuItem onClick={handleMenuCloseFilters}>Clear Filters</MenuItem> </Menu> <FormControl sx={{ ml: 2 }}> <Tooltip title="Density"> <IconButton onClick={handleMenuOpenDensity}> <img src={densityIcon} alt="density-icon"/> </IconButton> </Tooltip> </FormControl> <Typography sx={{cursor: 'pointer'}} color={'#2196F3'} onClick={handleMenuOpenDensity}>DENSITY</Typography> {/* Density菜单 */} <Menu anchorEl={anchorElDensity} open={Boolean(anchorElDensity)} onClose={handleMenuCloseDensity} anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }} transformOrigin={{ vertical: 'top', horizontal: 'left' }} > <MenuItem onClick={handleMenuCloseDensity}>Compact</MenuItem> <MenuItem onClick={handleMenuCloseDensity}>Standard</MenuItem> <MenuItem onClick={handleMenuCloseDensity}>Comfortable</MenuItem> </Menu> </div> {/* Search field on the right */} <div style={{ marginLeft: 'auto', height: 30 }}> <ThemeProvider theme={theme}> <TextField placeholder='Search' sx={{ height: 30, '& .MuiOutlinedInput-input': { padding: '0px', }, }} InputProps={{ startAdornment: ( <InputAdornment position="start"> <GridSearchIcon /> </InputAdornment> ), sx: { pr: '30px' }, }} InputLabelProps={{ shrink: true, sx: { mt: '-7px' }, }} /> </ThemeProvider> </div> </Toolbar> </Box> </> ), }}
4. 添加行内操作菜单
在组件的根Grid中添加行内操作的Menu:
<Grid item md={10}> <Box display="flex" justifyContent="flex-end" py={3}> <Button variant="contained"> <AddIcon /> Add New Form </Button> </Box> {/* 行内操作菜单 */} <Menu anchorEl={anchorElRowMenu} open={Boolean(anchorElRowMenu)} onClose={handleRowMenuClose} > <MenuItem onClick={handleRowMenuClose}>Action 1</MenuItem> <MenuItem onClick={handleRowMenuClose}>Action 2</MenuItem> <MenuItem onClick={handleRowMenuClose}>Action 3</MenuItem> </Menu> {/* DataGridPro */} <DataGridPro ... /> </Grid>
关键说明
- 每个菜单都使用独立的状态变量,彻底避免状态冲突。
- Menu组件和触发元素放在同一层级,确保
anchorEl能正确绑定点击源的DOM元素,菜单会在点击位置附近弹出。 - 移除了表格行内重复渲染的Filters Menu,解决了
anchorEl无效的报错。
内容的提问来源于stack exchange,提问作者Sanad Qazi
相关产品推荐
相关产品推荐

