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

求助:将React类组件转换为函数组件失败(基于旧版Material-UI的折叠菜单组件)

修复后的函数组件实现

我帮你排查了这个问题,类组件转函数组件后展开收起失效,大概率是状态更新逻辑或者闭包引用的问题导致的。下面是修复后的完整函数组件代码,以及关键的修复要点说明:

完整转换后的代码

首先是导入语句(仅替换类组件相关依赖为函数组件所需的useState):

import React, { useState } from "react"; 
import * as core from "@material-ui/core"; 
import { myData } from "./myData";

然后是函数组件的完整实现:

const MyFunctionComponent = () => {
  // 初始化状态,和类组件的state结构完全一致
  const [settings, setSettings] = useState([
    { id: "1", open: false }, 
    { id: "2", open: false }
  ]);

  // 处理菜单项点击,保持函数式更新确保拿到最新状态
  const handleClick = (id) => {
    setSettings(prevSettings => 
      prevSettings.map(item => 
        item.id === id ? { ...item, open: !item.open } : item
      )
    );
  };

  return (
    <div style={{ marginRight: "15px" }}>
      <core.List component="nav">
        {myData.map(each => {
          // 提前获取当前菜单项的设置,避免重复调用find,同时做空值校验
          const currentSetting = settings.find(item => item.id === each.id);
          if (!currentSetting) return null;

          return (
            <React.Fragment key={each.id}>
              <core.ListItem button onClick={() => handleClick(each.id)}>
                <core.ListItemText inset primary={each.nameHeader} />
                {currentSetting.open ? "expanded" : "collapsed"}
              </core.ListItem>
              <core.Divider />
              <core.Collapse 
                in={currentSetting.open} 
                timeout="auto" 
                unmountOnExit
              >
                <core.List component="div" disablePadding>
                  {each.subMenu.map(subData => (
                    <core.ListItem key={subData.id} button>
                      <core.ListItemText inset primary={subData.name} />
                    </core.ListItem>
                  ))}
                </core.List>
              </core.Collapse>
            </React.Fragment>
          );
        })}
      </core.List>
    </div>
  );
};

export default MyFunctionComponent;

关键修复要点

  1. 状态更新的函数式写法
    函数组件中使用useState更新依赖旧状态的新值时,必须用函数式更新(传入接收前状态的函数),这和类组件里setState(state => ...)的逻辑一致。这样能避免闭包陷阱,确保每次更新都基于最新的状态值,这是你转换后功能失效的核心原因。

  2. 优化状态查找与空值校验
    在渲染循环中提前调用find获取当前菜单项的设置,避免重复执行相同的查找逻辑以提升性能;同时增加空值校验,防止myData中存在settings里没有对应id的项时出现Cannot read property 'open' of undefined的错误。

  3. 移除this引用
    函数组件中直接使用组件内定义的变量和函数,不需要像类组件那样依赖this,这是函数组件的基本语法规范。

额外提醒

如果后续myData中新增了菜单项,记得同步更新useState的初始settings数组,保证每个菜单项都有对应的open状态项,否则新增的菜单项将无法正常展开收起。

内容的提问来源于stack exchange,提问作者hope

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 19:18:14