React中如何用单个onClick事件处理多布尔状态控制侧边栏下拉菜单
问题原因
你之前的复用写法失效核心原因是对象键名的语法问题:你直接在setState的对象里写value作为键,JS会把它解析为固定的字符串键"value",而不是你传入的动态变量,所以实际上你每次更新的都是状态里不存在的value字段,原有菜单的状态完全没被修改,自然不会生效。
最小改动修复方案
只需要把对象键名换成ES6的计算属性名语法,用方括号包裹动态变量即可,同时推荐用函数式更新状态的写法,避免闭包导致的状态更新异常:
const clickHandler = (key, e) => { e.preventDefault(); setState(prevState => ({ ...prevState, [key]: !prevState[key] })); };
渲染部分的调用方式调整为传入对应状态的键名字符串即可:
<div onClick={(e) => clickHandler('one', e)}>First</div> {state.one && <div>Something</div>} <div onClick={(e) => clickHandler('two', e)}>Second</div> {state.two && <div>Something</div>}
注意这里传入的是字符串形式的键名
'one',不是变量one,同时要把事件对象e透传给处理函数。
更简洁的全复用方案
如果想彻底消除重复代码,可以把所有菜单的配置抽成数组,遍历渲染,后续新增/修改菜单只需要调整配置数组即可:
// 菜单配置,可任意扩展 const menuList = [ { id: 'one', title: 'First', content: 'First menu content' }, { id: 'two', title: 'Second', content: 'Second menu content' }, { id: 'three', title: 'Third', content: 'Third menu content' }, { id: 'four', title: 'Fourth', content: 'Fourth menu content' }, { id: 'five', title: 'Fifth', content: 'Fifth menu content' }, { id: 'six', title: 'Sixth', content: 'Sixth menu content' }, ] function Sidebar() { const [openState, setOpenState] = useState({ one: false, two: false, three: false, four: false, five: false, six: false, }); const toggleMenu = (menuId, e) => { e.preventDefault(); setOpenState(prev => ({ ...prev, [menuId]: !prev[menuId] })); }; return ( <div className="sidebar"> {menuList.map(menu => ( <div key={menu.id} className="menu-item"> <div className="menu-title" onClick={(e) => toggleMenu(menu.id, e)}> {menu.title} </div> {openState[menu.id] && <div className="menu-content">{menu.content}</div>} </div> ))} </div> ) }
可选优化:手风琴模式
如果你需要实现「每次只展开一个菜单」的手风琴效果,可以直接把状态改成存储当前展开的菜单ID,不用存储6个布尔值,代码更简洁:
const [activeMenuId, setActiveMenuId] = useState(null); const toggleMenu = (menuId, e) => { e.preventDefault(); // 如果点击的是已经展开的菜单就收起,否则切换为当前点击的菜单 setActiveMenuId(prev => prev === menuId ? null : menuId); }; // 渲染时判断逻辑改为 {activeMenuId === menu.id && <div className="menu-content">{menu.content}</div>}
内容的提问来源于stack exchange,提问作者HongCoder
相关产品推荐
相关产品推荐

