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: {student.grades[0]}%</p> <p>Test 2: {student.grades[1]}%</p> <p>Test 3: {student.grades[2]}%</p> <p>Test 4: {student.grades[3]}%</p> <p>Test 5: {student.grades[4]}%</p> <p>Test 6: {student.grades[5]}%</p> <p>Test 7: {student.grades[6]}%</p> <p>Test 8: {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: {student.grades[0]}%</p> <p>Test 2: {student.grades[1]}%</p> <p>Test 3: {student.grades[2]}%</p> <p>Test 4: {student.grades[3]}%</p> <p>Test 5: {student.grades[4]}%</p> <p>Test 6: {student.grades[5]}%</p> <p>Test 7: {student.grades[6]}%</p> <p>Test 8: {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
相关产品推荐
相关产品推荐

