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

React使用useState控制列表单个元素展开/收起的实现问题咨询

React 单列表项独立展开解决方案

问题原因

你当前把下拉状态dropDown、图标状态icon定义在了列表的父组件层级,所有列表项共用同一个全局状态,一旦触发状态更新,所有列表项都会读取新的状态值,自然会同时显隐。

推荐实现方案

方案1:状态下沉到独立子组件(最推荐,耦合度最低)

把单个学生项的逻辑抽成独立的StudentItem组件,每个组件内部独立维护自身的下拉状态、切换逻辑,不同组件的状态完全隔离,互不影响。

  • 父组件仅负责遍历学生数组,传递单个学生数据给子组件即可

示例代码:

// 父组件代码
import StudentItem from './StudentItem'

function StudentList() {
  // 你的学生数组,每个项需要有唯一id字段
  const studentList = [
    {id: 1, name: '张三', age: 18, class: '高一1班'},
    {id: 2, name: '李四', age: 17, class: '高一2班'}
  ]

  return (
    <div className="student-list">
      {studentList.map(student => (
        <StudentItem key={student.id} student={student} />
      ))}
    </div>
  )
}
// 子组件 StudentItem.jsx 代码
import { useState } from 'react'

export default function StudentItem({ student }) {
  // 每个子组件自己维护下拉状态和图标状态
  const [dropDown, setDropDown] = useState('hidden')
  const [icon, setIcon] = useState('\u002B') // 加号Unicode,可替换为你用的字符

  const handleHidden = () => {
    if (dropDown === 'hidden') {
      setDropDown('active')
      setIcon('\u2212') // 减号Unicode,可替换为你用的字符
    } else {
      setDropDown('hidden')
      setIcon('\u002B')
    }
  }

  return (
    <div className="student-item">
      <span onClick={handleHidden} className="toggle-btn">
        {icon} {student.name}
      </span>
      <ul style={{display: dropDown === 'active' ? 'block' : 'none'}}>
        <li>年龄:{student.age}</li>
        <li>班级:{student.class}</li>
        {/* 其他你需要展示的下拉内容 */}
      </ul>
    </div>
  )
}

方案2:父组件存储激活项标识(无需抽离子组件)

如果不想抽离组件,也可以修改父组件的状态为存储当前展开项的唯一标识,而非全局的显隐状态:

  • 单选场景(每次仅允许展开一个列表项):状态存储当前激活的学生id,初始值为null
  • 多选场景(允许多个列表项同时展开):状态存储Set结构,保存所有已展开的学生id

以下是单选场景示例代码:

import { useState } from 'react'

function StudentList() {
  const studentList = [/* 你的学生数组 */]
  // 存储当前展开的学生id,null代表没有展开项
  const [activeId, setActiveId] = useState(null)

  const handleToggle = (studentId) => {
    // 点击已展开的项则收起,否则展开当前点击项
    setActiveId(activeId === studentId ? null : studentId)
  }

  return (
    <div className="student-list">
      {studentList.map(student => (
        <div key={student.id} className="student-item">
          <span onClick={() => handleToggle(student.id)} className="toggle-btn">
            {activeId === student.id ? '\u2212' : '\u002B'} {student.name}
          </span>
          <ul style={{display: activeId === student.id ? 'block' : 'none'}}>
            <li>年龄:{student.age}</li>
            <li>班级:{student.class}</li>
          </ul>
        </div>
      ))}
    </div>
  )
}

注意:遍历渲染列表项时必须给每个项设置唯一的key属性,优先使用学生的唯一业务id,不要直接用数组下标作为key。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 12:00:01