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

React递归组件中修改子项状态时如何保持下拉菜单展开

问题根因

你遇到的展开下拉自动关闭的核心原因是递归组件RecursiveComponent定义在了App组件内部:

  • 每次点击复选框触发setData修改根状态时,App组件都会重新渲染
  • 重新渲染时会生成全新的RecursiveComponent函数实例,React判定这是不同的组件类型,会直接卸载旧组件、挂载新组件
  • 旧组件内部存储的showChildren状态会随着组件卸载被销毁,新挂载的组件showChildren默认值为false,就出现了展开项自动关闭的现象
修复方案

把RecursiveComponent移到App组件外部定义,将需要用到的选中回调方法通过props透传即可,修正后的完整代码如下:

import React, { useState } from "react";
import "./styles.css";

const beData = [
  {
    id: 1,
    label: "fruit",
    checked: false,
    children: [
      { id: 23, label: "apples", checked: false },
      { id: 21, label: "orange", checked: false }
    ]
  },
  { id: 32, label: "dairy", checked: false }
];

// 递归组件移到App外部定义,避免重复生成组件实例
const RecursiveComponent = ({ data, onCheck }) => {
  const [showChildren, setShowChildren] = useState(false);
  return (
    <div>
      <label style={{ display: "flex", alignItems: "center" }}>
        <button onClick={() => setShowChildren(!showChildren)} type="button">
          v
        </button>
        <input
          checked={data.checked}
          onChange={() => onCheck(data.id)}
          type="checkbox"
        />
        <p>{data.label}</p>
      </label>

      <div style={{ paddingLeft: "30px" }}>
        {data.children?.length > 0 && showChildren &&
          data.children.map((child) => (
            <RecursiveComponent 
              data={child} 
              key={child.id} 
              onCheck={onCheck} 
            />
          ))
        }
      </div>
    </div>
  );
};

export default function App() {
  const [data, setData] = useState(beData);
  const recursiveMap = (data, key) => {
    return data.map((i) => {
      let result = { ...i };
      if (i.id === key) result = { ...i, checked: !i.checked };
      if (i.children?.length) result.children = recursiveMap(i.children, key);
      return result;
    });
  };

  const handleCheck = (key) => setData(recursiveMap(data, key));

  return (
    <div className="App">
      {data.map((item) => (
        <RecursiveComponent 
          data={item} 
          key={item.id} 
          onCheck={handleCheck} 
        />
      ))}
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 19:57:03