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

React中如何通过ID切换嵌套数组对象的isExpanded属性并更新状态

React 递归切换嵌套数组对象的isExpanded状态并更新组件状态

要实现点击ID切换嵌套数组中对应对象的isExpanded属性,核心是遵循React状态不可变的原则,通过递归遍历并复制数据结构来修改目标属性,再更新组件状态。

完整实现代码

假设你的组件中使用useState管理这份嵌套数据:

import { useState } from 'react';

// 定义数据类型(TypeScript可选)
type OutlineItem = {
  id: string;
  title: string;
  isExpanded: boolean;
  children: OutlineItem[];
};

const MyComponent = () => {
  // 初始数据
  const initialData: OutlineItem[] = [
    {
      id: '1',
      title: 'Introduction to Programming',
      isExpanded: true,
      children: [
        {
          id: '1.1',
          title: 'What is programming?',
          isExpanded: false,
          children: [
            { id: '1.1.1', title: 'What is programming?', isExpanded: false, children: [] },
            { id: '1.1.2', title: 'What is programming?', isExpanded: false, children: [] },
          ],
        },
        {
          id: '1.2',
          title: 'Programming languages',
          isExpanded: false,
          children: [
            { id: '1.2.1', title: 'Programming languages', isExpanded: false, children: [] },
            { id: '1.2.2', title: 'Programming languages', isExpanded: false, children: [] },
          ],
        },
      ],
    },
  ];

  const [outlineData, setOutlineData] = useState<OutlineItem[]>(initialData);

  const handleExpandOutlineItem = (id: string) => {
    // 递归函数:遍历并修改目标项的isExpanded
    const toggleItemExpanded = (items: OutlineItem[]): OutlineItem[] => {
      return items.map(item => {
        // 找到目标ID的项,复制并切换isExpanded
        if (item.id === id) {
          return { ...item, isExpanded: !item.isExpanded };
        }
        // 未找到则递归处理子节点,保留其他属性不变
        return { ...item, children: toggleItemExpanded(item.children) };
      });
    };

    // 使用函数式更新确保拿到最新状态
    setOutlineData(prevData => toggleItemExpanded(prevData));
  };

  // 渲染逻辑示例
  const renderItems = (items: OutlineItem[]) => {
    return items.map(item => (
      <div key={item.id}>
        <button onClick={() => handleExpandOutlineItem(item.id)}>
          {item.isExpanded ? '▼' : '▶'} {item.title}
        </button>
        {item.isExpanded && item.children.length > 0 && (
          <div style={{ marginLeft: 20 }}>
            {renderItems(item.children)}
          </div>
        )}
      </div>
    ));
  };

  return <div>{renderItems(outlineData)}</div>;
};

export default MyComponent;

关键说明

  1. 不可变性处理:每次修改都通过扩展运算符{...item}复制原对象,避免直接修改原状态数据,符合React的状态更新规范。
  2. 递归遍历:toggleItemExpanded函数会遍历每一层的children,不管嵌套深度多少,都能找到目标ID的项并切换状态。
  3. 函数式状态更新:调用setOutlineData时传入函数,确保使用最新的prevData进行修改,避免因闭包导致的状态过期问题。
  4. 渲染联动:状态更新后,组件会自动重新渲染,根据isExpanded的值控制子节点的显示/隐藏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 00:57:28