基于HeadlessUI与React的移动端嵌套抽屉导航问题排查
移动端嵌套抽屉导航问题:点击分类始终显示最后一个分类内容
我正在复刻移动端嵌套抽屉导航,抽屉能正常打开,但点击任意分类时,始终只显示最后一个分类(比如Events、Retailers)的内容,而非选中的分类。
菜单JSON
{"items": [{"title": "Vaporizers","url": "","items": [{"title": "FOR FLOWER & CONCENTRATES","items": [{"title": "COMPANY PLUS","url": "/products/COMPANY-plus"},{"title": "COMPANY MINI","url": "/products/COMPANY-mini"}],"url": "/collections/dry-herb-and-concentrate-vaporizers"},{"title": "FOR OIL EXTRACT PODS","items": [{"title": "COMPANY ERA","url": "/products/COMPANY-era"},{"title": "ERA PRO","url": "/products/era-pro"}],"url": "/collections/oil-extract-vape-pens"},{"title": "ON SALE","items": [],"url": "/collections/sale"}],"useShowcaseComponent": true},{"title": "Cannabis","url": "","items": [{"title": "COMPANY Infused","url": "/products/cannabis/COMPANY-infused"},{"title": "COMPANY Live Rosin","url": "/products/cannabis/COMPANY-live"},{"title": "COMPANY Diamonds","url": "/products/cannabis/COMPANY-diamonds"}]},{"title": "Find","url": "","items": [{"title": "Events","url": "/pages/COMPANY-events"},{"title": "Retailers","url": "/pages/store-locator"}]}]}
Header组件代码
<MenuDrawer isOpen={isMenuOpen} onClose={closeMenu}> <TopLevelMenuNav menu={menu} closeMenuItem={closeMenuItem} openMenuItem={openMenuItem} isMenuItemOpen={isMenuItemOpen} /> </MenuDrawer>
TopLevelMenuNav组件代码
{(menu?.items || []).map((category) => ( <div key={category.title}> <button onClick={openMenuItem} className="flex flex-row justify-between p-4 align-middle text-2xl" > {category.title} <ChevronRightIcon className="ml-1 h-4 w-4 self-center" /> </button> <MenuDrawer isOpen={isMenuItemOpen} onClose={closeMenuItem}> <MenuItemNav category={category} /> </MenuDrawer> </div> ))}
MenuItemNav组件代码
<div className="flex flex-col"> {category.items.map((section) => ( <div key={section.title} className="flex flex-col hover:bg-gray-50"> <a href={section.url} className="py-4 px-6 font-normal text-gray-500"> {section.title} </a> {section?.items && ( <div className="flex flex-col pl-8"> {section.items.map((item) => ( <div key={item.title} className="flex hover:bg-gray-50"> <a href={item.url} className="py-2 font-semibold text-gray-900" > {item.title} </a> </div> ))} </div> )} </div> ))} </div>
我曾尝试使用useState来设置MenuItemNav组件中显示的内容,但问题依旧,仍只显示最后一个分类的内容。
问题原因及解决方案
问题核心
所有分类共用同一个布尔型isMenuItemOpen状态,且每个分类都渲染了独立的MenuDrawer。点击任意分类触发openMenuItem时,所有抽屉的isOpen都会变为true,但DOM渲染顺序中最后一个抽屉会覆盖前面的,导致看起来只显示最后一个分类的内容。
修改步骤
- 调整状态类型:将单个布尔值
isMenuItemOpen改为记录当前打开分类的标识(比如分类标题),用于精准控制对应抽屉的显示。 - 更新点击事件:点击分类按钮时,把当前分类的标识存入状态;关闭抽屉时清空状态。
- 匹配抽屉显示条件:每个抽屉只在当前分类标识与状态匹配时才打开。
修改后的代码示例
Header组件(状态调整)
// 替换原有的isMenuItemOpen状态 const [openCategory, setOpenCategory] = useState(null); // 更新打开/关闭函数 const openMenuItem = (categoryTitle) => { setOpenCategory(categoryTitle); }; const closeMenuItem = () => { setOpenCategory(null); }; // 传递更新后的props给TopLevelMenuNav <MenuDrawer isOpen={isMenuOpen} onClose={closeMenu}> <TopLevelMenuNav menu={menu} closeMenuItem={closeMenuItem} openMenuItem={openMenuItem} openCategory={openCategory} /> </MenuDrawer>
TopLevelMenuNav组件(匹配显示条件)
{(menu?.items || []).map((category) => ( <div key={category.title}> <button onClick={() => openMenuItem(category.title)} className="flex flex-row justify-between p-4 align-middle text-2xl" > {category.title} <ChevronRightIcon className="ml-1 h-4 w-4 self-center" /> </button> <MenuDrawer isOpen={openCategory === category.title} onClose={closeMenuItem} > <MenuItemNav category={category} /> </MenuDrawer> </div> ))}
这样修改后,每个分类的抽屉只有在当前选中的分类标识与状态匹配时才会打开,不会再出现多个抽屉同时显示、最后一个覆盖的问题。
内容的提问来源于stack exchange,提问作者G.Rose
相关产品推荐
相关产品推荐

