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

React组件onClick事件处理:实现点击展开一个面板其余自动关闭

核心改造思路

当前每个ListItem组件独立维护自身的展开状态,组件之间没有状态关联,所以无法实现互斥展开。需要把展开状态提升到所有ListItem的公共父组件中,通过唯一标识符记录当前处于展开状态的模块,点击新模块时直接更新该标识符即可自动关闭原有展开的模块。

父组件实现

在渲染四个列表模块的父组件中统一维护展开状态,将激活状态和切换方法通过props传递给子组件:

import { useState } from 'react';
import ListItem from './ListItem';

// allListData为你存放四个模块所有数据的数组
function ListContainer({ allListData }) {
  // 存储当前展开项的唯一标识,null表示无展开项
  const [activeId, setActiveId] = useState(null);

  const handleToggle = (id) => {
    // 点击已展开项则收起,否则切换为点击的项
    setActiveId(activeId === id ? null : id);
  };

  return (
    <div className="List-wrapper">
      {allListData.map((dataItem, idx) => (
        <ListItem
          key={idx}
          listNumber={idx + 1}
          listData={dataItem}
          isActive={activeId === idx + 1}
          onToggle={handleToggle}
        />
      ))}
    </div>
  );
}

子组件改造

删除ListItem内部的独立状态,改用父组件传递的props控制展开逻辑:

function ListItem({ listNumber, listData, isActive, onToggle }) {
  return (
    <div className="List">
      <div 
        className="List-section" 
        onClick={() => onToggle(listNumber)}
      >
        <div className="Section-item">{listNumber}</div>
        <p className="Section-title">{listData.title}</p>
      </div>
      {isActive && (
        <div className="List-paragraph">
          {listData.items.map((paragraphItem, index) => (
            <div className="Paragraph-container" key={index}>
              <CheckedIcon  />
              <p className="Paragraph-item">{paragraphItem}</p>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

补充说明

如果你的listNumber存在重复的情况,可以改用数组索引作为唯一标识传递和判断。如果不需要支持点击已展开项自动收起的效果,直接把handleToggle方法内的逻辑修改为setActiveId(id)即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 00:36:04