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

React遍历API数据时如何仅展开单个Div组件

解决React列表项展开/收起同步的问题

这是个非常常见的React状态管理小坑——你现在用了一个**全局的单一状态isCollapsed**来控制所有学生卡片的展开/收起状态,所有卡片都会绑定这个相同的状态值,所以一点击就全部跟着切换了。咱们有两种简单的方法可以解决这个问题:

方法一:用对象存储每个列表项的独立状态

我们可以把原来的单一布尔值状态,改成一个以学生ID为键的对象,用来单独记录每个学生卡片的折叠状态:

export default function StudentsList({ students }) {
  // 初始化状态:所有学生默认折叠
  const [collapsedStates, setCollapsedStates] = useState(
    students.reduce((acc, student) => {
      acc[student.id] = true;
      return acc;
    }, {})
  );

  // 点击时只切换对应学生ID的状态
  const handleCollapse = (studentId) => {
    setCollapsedStates(prev => ({
      ...prev,
      [studentId]: !prev[studentId]
    }));
  };

  return (
    <div className={studentsBox}>
      {students.map((student) => (
        <div className={card} key={student.id}>
          <div 
            className={plus} 
            onClick={() => handleCollapse(student.id)}
          >
            {collapsedStates[student.id] ? '+' : '-'}
          </div>
          <div className={collapsedStates[student.id] ? collapse : ''}>
            <p>Test 1: &nbsp;&nbsp; {student.grades[0]}%</p>
            <p>Test 2: &nbsp;&nbsp; {student.grades[1]}%</p>
            <p>Test 3: &nbsp;&nbsp; {student.grades[2]}%</p>
            <p>Test 4: &nbsp;&nbsp; {student.grades[3]}%</p>
            <p>Test 5: &nbsp;&nbsp; {student.grades[4]}%</p>
            <p>Test 6: &nbsp;&nbsp; {student.grades[5]}%</p>
            <p>Test 7: &nbsp;&nbsp; {student.grades[6]}%</p>
            <p>Test 8: &nbsp;&nbsp; {student.grades[7]}%</p>
          </div>
        </div>
      ))}
    </div>
  );
}

这个方法的核心是:用学生的唯一ID作为标识,让每个卡片对应状态对象里的一个独立属性,点击时只修改对应ID的状态值,这样就不会影响其他卡片了。

方法二:拆分独立的子组件(更推荐)

如果你的学生卡片后续可能会增加更多交互逻辑,把每个卡片拆成独立的子组件会更清晰,每个子组件自己维护自己的展开状态:

// 独立的学生卡片组件
function StudentCard({ student }) {
  const [isCollapsed, setIsCollapsed] = useState(true);
  
  const handleCollapse = () => {
    setIsCollapsed(prev => !prev);
  };

  return (
    <div className={card}>
      <div className={plus} onClick={handleCollapse}>
        {isCollapsed ? '+' : '-'}
      </div>
      <div className={isCollapsed ? collapse : ''}>
        <p>Test 1: &nbsp;&nbsp; {student.grades[0]}%</p>
        <p>Test 2: &nbsp;&nbsp; {student.grades[1]}%</p>
        <p>Test 3: &nbsp;&nbsp; {student.grades[2]}%</p>
        <p>Test 4: &nbsp;&nbsp; {student.grades[3]}%</p>
        <p>Test 5: &nbsp;&nbsp; {student.grades[4]}%</p>
        <p>Test 6: &nbsp;&nbsp; {student.grades[5]}%</p>
        <p>Test 7: &nbsp;&nbsp; {student.grades[6]}%</p>
        <p>Test 8: &nbsp;&nbsp; {student.grades[7]}%</p>
      </div>
    </div>
  );
}

// 父组件:学生列表
export default function StudentsList({ students }) {
  return (
    <div className={studentsBox}>
      {students.map((student) => (
        <StudentCard key={student.id} student={student} />
      ))}
    </div>
  );
}

这种方式下,每个StudentCard都有自己的isCollapsed状态,完全独立于其他卡片,状态管理更清晰,也符合React组件单一职责的原则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 20:52:31