如何在React中程序化生成多组可折叠菜单?
动态可折叠菜单的正确实现方案
问题分析
你遇到的两个核心问题:
- 用普通对象
states存状态:React无法追踪普通变量的变化,修改后不会触发组件重渲染,菜单状态自然不会更新;而且每次组件渲染都会重置这个对象,状态根本留不住。 - 内嵌
script标签操作DOM:React的渲染逻辑不支持这种写法,<script>内容不会被执行,且即使能执行,也可能在元素未挂载到真实DOM时运行,导致找不到元素报错。
正确实现方式
方案1:用对象存储每个菜单的展开状态
通过useState管理一个状态对象,键为菜单的唯一key,值为布尔值控制展开/折叠:
import { useState } from 'react'; function Systems(props) { // 初始化所有菜单为折叠状态 const [expandedMenus, setExpandedMenus] = useState(() => { const initialState = {}; Object.keys(System_Definitions[props.type]).forEach(key => { initialState[key] = false; }); return initialState; }); // 切换指定菜单的展开状态 const toggleMenu = (key) => { setExpandedMenus(prevState => ({ ...prevState, [key]: !prevState[key] })); }; return ( <div className={styles.formContainer}> <p className={styles.formContainerLabel}>{props.type.toUpperCase()}</p> {Object.keys(System_Definitions[props.type]).map((key) => { const system = System_Definitions[props.type][key]; return ( // 必须给循环元素加唯一key,这是React的要求 <div key={key} className={styles.formContainer}> <p className={styles.formContainerLabel} onClick={() => toggleMenu(key)} > {key.toUpperCase() + ' - ' + system.label.toUpperCase()} </p> <div id={key} className={expandedMenus[key] ? '' : styles.formContainerContentHidden} > <TextInput label={'Life'} name={'life'} placeholder={system.life} /> </div> </div> ); })} </div> ); }
方案2:用Set存储已展开的菜单key(更简洁)
如果只需要记录哪些菜单是展开的,用Set比对象更轻便:
import { useState } from 'react'; function Systems(props) { const [expandedKeys, setExpandedKeys] = useState(new Set()); const toggleMenu = (key) => { setExpandedKeys(prevSet => { const newSet = new Set(prevSet); prevSet.has(key) ? newSet.delete(key) : newSet.add(key); return newSet; }); }; return ( <div className={styles.formContainer}> <p className={styles.formContainerLabel}>{props.type.toUpperCase()}</p> {Object.keys(System_Definitions[props.type]).map((key) => { const system = System_Definitions[props.type][key]; const isExpanded = expandedKeys.has(key); return ( <div key={key} className={styles.formContainer}> <p className={styles.formContainerLabel} onClick={() => toggleMenu(key)} > {key.toUpperCase() + ' - ' + system.label.toUpperCase()} </p> <div id={key} className={isExpanded ? '' : styles.formContainerContentHidden} > <TextInput label={'Life'} name={'life'} placeholder={system.life} /> </div> </div> ); })} </div> ); }
核心原理
React的状态必须通过useState/useReducer这类钩子管理,这样React才能监听状态变化并自动触发组件重渲染,从而更新UI。永远不要用普通变量存需要驱动UI变化的状态,也不要在React组件里用内嵌script操作DOM——React的设计理念就是用状态控制UI,而非直接操作DOM。
内容的提问来源于stack exchange,提问作者Aitchbar
相关产品推荐
相关产品推荐

