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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 08:03:29