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

如何修复MUI中`anchorEl`属性无效及菜单定位错误问题

问题原因
  1. 重复渲染Menu组件:当前在DataGrid的status列renderCell中,每一行都会渲染一个Filters的Menu,多个Menu实例共享同一个anchorElFilters状态,造成状态混乱,触发anchorEl无效的报错。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 04:45:57