React中循环渲染列表时基于id控制单个元素下拉内容显隐的问题
问题根源
- 你定义的
display是全局公用状态,所有循环生成的学生卡片都共用这一个开关,所以点击任意按钮都会触发所有卡片的显隐切换。你虽然存了被点击元素的唯一id到state,但完全没用来判断当前卡片要不要展示详情。 - 监听
active变化的useEffect属于多余逻辑,完全不需要额外维护display状态,直接用当前遍历到的学生id和active.activeStudent做比对,就能判断当前卡片的显隐状态。
修复后完整代码
import React, { useState } from 'react'; import '../style/skeleton.css' import '../style/style.css' // 这里直接解构props拿到传递进来的student数组,写法更清晰 export default function Body({ student }) { // 只需要存当前激活的学生id即可,不需要额外的display状态 const [active, setActive] = useState({ activeStudent: null, }); const handleClick = (id) => { // 点击逻辑:如果当前点击的是已经展开的学生,就收起,否则展开当前点击的学生 setActive({ activeStudent: active.activeStudent === id ? null : id }) }; return ( <div> {student.map((data) => { // 核心判断:当前遍历的学生id是否等于激活的id,决定当前卡片的显隐 const isCurrentActive = data.id === active.activeStudent; return ( <div key={data.id} className="row border"> <div className="two-thirds column"> <h3>{data.firstName} {data.lastName}</h3> <button onClick={() => handleClick(data.id)}> {isCurrentActive ? '-' : '+'} </button> {isCurrentActive && ( <div> <p>{data.addional} additonal data</p> </div> )} </div> </div> ) })} </div> ); }
核心逻辑说明
- 循环渲染的列表项做状态判断时,永远要和当前遍历项的唯一标识做比对,不要用全局布尔状态控制所有项的展示
- 可以通过已有状态推导出来的内容,不要单独存额外状态,这里要不要展示详情完全可以通过激活id和当前项id的比对结果推导,不需要单独维护
display状态 - 非必要不要随便用useEffect监听状态再更新其他状态,简单的状态更新直接在事件回调里处理即可,避免出现多余的副作用逻辑漏洞
内容的提问来源于stack exchange,提问作者Jojo designs
相关产品推荐
相关产品推荐

