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
相关产品推荐
相关产品推荐

