我正在尝试使用 React 的 setState 钩子打开和关闭我的 Material UI <Menu />
。我以 this sandbox code 为例。然而,我的实现似乎并没有关闭菜单。
打开它工作正常(使用 setAnchorEl(event.currentTarget)
),但使用 setAnchorEl(null)
关闭它不知道。函数 handleClose()
运行(console.log()
打印正常),但 anchorEl
的值没有改变。我使用 useEffect()
钩子检查了这一点,它在初始化时打印 null,打开时打印 <li>
元素,尝试关闭时不打印。
我已经尝试使用 let
而不是 const
作为 (set
)anchorEl
和 isProfileMenuOpen
定义,但这不起作用。我还检查了 this post,但就我所见,我的 <MenuAppBar />
组件并未卸载(它无条件地在根部呈现)。
我一定是忽略了一些细节。有人能在下面看到吗?
const {useState, useEffect} = React;
const { ClickAwayListener, Menu, MenuItem, IconButton } = MaterialUI;
function MenuAppBar(props) {
const [anchorEl, setAnchorEl] = useState(null);
const isProfileMenuOpen = Boolean(anchorEl);
// For debugging purposes:
useEffect(() => {
console.log(anchorEl);
}, [anchorEl]);
const handleClose = () => {
console.log("Closing menu"); // This prints, so function runs
setAnchorEl(null); // This doesn't seem to set anchorEl to null
};
const handleProfileMenuOpen = (event) => {
setAnchorEl(event.currentTarget); // This does work
}
return (
<ClickAwayListener onClickAway={handleClose}>
<MenuItem onClick={handleProfileMenuOpen}>
<IconButton
style={{ backgroundColor: "#F5B089" }}
/>
<Menu
anchorEl={anchorEl}
keepMounted
open={isProfileMenuOpen}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem>Logout</MenuItem>
</Menu>
</MenuItem>
</ClickAwayListener>
);
}
ReactDOM.render(
<MenuAppBar />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script>
<div id="react"></div>
答案 0 :(得分:4)
发生的事情是在调用 handleClose
之后,再次调用了 handleProfileMenuOpen
。所以你最终在同一个点击事件中两次调用 setAnchorEl
,所以 React 只重新渲染一次组件 - 将它设置为 handleProfileMenuOpen
与 Stack Snippet 中相同的 li
)。
如果您阻止事件传播,它会阻止 handleProfileMenuOpen
调用:
const handleClose = (event) => {
console.log("Closing menu");
setAnchorEl(null);
event.stopPropagation(); // <=====
};
现场示例:
const {useState, useEffect} = React;
const { ClickAwayListener, Menu, MenuItem, IconButton } = MaterialUI;
function MenuAppBar(props) {
const [anchorEl, setAnchorEl] = useState(null);
const isProfileMenuOpen = Boolean(anchorEl);
console.log(anchorEl);
const handleClose = (event) => {
console.log("Closing menu"); // This prints, so function runs
setAnchorEl(null); // This doesn't seem to set anchorEl to null
event.stopPropagation();
};
const handleProfileMenuOpen = (event) => {
console.log("Opening menu");
setAnchorEl(event.currentTarget); // This does work
}
return (
<ClickAwayListener onClickAway={handleClose}>
<MenuItem onClick={handleProfileMenuOpen}>
<IconButton
style={{ backgroundColor: "#F5B089" }}
/>
<Menu
anchorEl={anchorEl}
keepMounted
open={isProfileMenuOpen}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem>Logout</MenuItem>
</Menu>
</MenuItem>
</ClickAwayListener>
);
}
ReactDOM.render(
<MenuAppBar />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script>
<div id="react"></div>
旁注:如果您想在组件重新渲染时看到 anchorEl
发生变化,则不需要 useEffect
调用,只需将其记录在组件函数的顶层(或放置一个const [anchorEl ...
行上的断点)。请记住,每次呈现组件时都会调用组件函数,以便始终向您显示 anchorEl
的最新版本。