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

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(),简化事件绑定

  1. 删除closeMenu中的e.stopPropagation(),让事件正常冒泡:
function closeMenu(e){
    setIsOpen(false);
    // 移除e.stopPropagation()
}
  1. 菜单项直接调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 05:21:13