MUI Drawer偶现无法关闭:约每5次操作出现1次异常
MUI Drawer点击菜单项后偶尔无法关闭的问题排查与解决
我用MUI实现了一个Drawer,预期点击菜单项后抽屉会关闭,但大概每5次操作就会出现1次抽屉保持打开的情况。控制台打印显示isOpen已经是false,但抽屉视觉上仍处于打开状态。
相关代码
NAVBAR 组件
const [hamburgerMenuIsOpen, setHamburgerMenuIsOpen] = useState(false); function handleClickOnHamburgerMenu() { setHamburgerMenuIsOpen(true); } // [.....] return( <> // MORE COMPONENTS <IconButton color="inherit" aria-label="Menu" onClick={handleClickOnHamburgerMenu} key="hamburger_menu" size="large"> <MenuIcon sx={classes.topNavBarIconMenu}/> </IconButton> <HamburgerMenu client={client} isOpen={hamburgerMenuIsOpen} setIsOpen={setHamburgerMenuIsOpen} /> </> )
HAMBURGER MENU 组件
const {client, isOpen, setIsOpen} = props; // [.....] function closeMenu(e){ setIsOpen(false); e.stopPropagation() } console.log('in hamburger_menu - about to redraw component. isOpen: ', isOpen) return ( <> <Drawer open={isOpen} onClose={(e) => closeMenu(e)} anchor='right' key='navBarDrwr' > <List> <ListItem component={Link} to="" button key="Home" onClick={(e) => closeMenu(e)}> <ListItemText primary="Home"/> </ListItem> // [...MORE LIST ITEMS...] </List> </Drawer> </> )
问题原因
核心冲突在于e.stopPropagation()和Link组件的跳转逻辑:
- 点击菜单项时,
closeMenu里的e.stopPropagation()阻止了事件冒泡,但Link的页面跳转可能抢在Drawer状态更新完成前触发,导致MUI的Drawer组件没有正确同步DOM状态。 - 同时
Drawer的onClose和菜单项的onClick重复绑定关闭逻辑,可能引发事件处理顺序的混乱。
解决方案
方案1:移除e.stopPropagation(),简化事件绑定
- 删除
closeMenu中的e.stopPropagation(),让事件正常冒泡:
function closeMenu(e){ setIsOpen(false); // 移除e.stopPropagation() }
- 菜单项直接调用
setIsOpen(false),避免重复处理:
<ListItem component={Link} to="" button key="Home" onClick={() => setIsOpen(false)}> <ListItemText primary="Home"/> </ListItem>
方案2:用useEffect强制同步Drawer状态
如果方案1仍有问题,通过useRef和useEffect监听isOpen变化,手动触发Drawer关闭:
import { useRef, useEffect } from 'react'; import { Drawer } from '@mui/material'; const HamburgerMenu = ({ isOpen, setIsOpen }) => { const drawerRef = useRef(null); useEffect(() => { if (!isOpen && drawerRef.current) { drawerRef.current.close(); } }, [isOpen]); return ( <Drawer ref={drawerRef} open={isOpen} onClose={() => setIsOpen(false)} anchor='right' key='navBarDrwr' > <List> <ListItem component={Link} to="" button key="Home" onClick={() => setIsOpen(false)}> <ListItemText primary="Home"/> </ListItem> // [...MORE LIST ITEMS...] </List> </Drawer> ); };
方案3:延迟跳转确保状态更新完成
若需要保留Link的跳转逻辑,可给跳转加短延迟,让Drawer状态先更新:
function handleMenuItemClick(path) { setIsOpen(false); setTimeout(() => { window.location.href = path; }, 100); // 100ms足够完成Drawer状态同步 } // 替换Link为普通button,手动处理跳转 <ListItem button key="Home" onClick={() => handleMenuItemClick("")}> <ListItemText primary="Home"/> </ListItem>
内容的提问来源于stack exchange,提问作者VikR
相关产品推荐
相关产品推荐

