React中详情弹窗如何仅展示props列表内选中的单条记录
问题根因
这个问题和事件冒泡无关,stopPropagation不生效是因为代码本身存在三个逻辑错误:
- 模态框组件被放在了
map遍历循环内部,只要isModalTraineeDetailsVisible状态变为true,所有遍历行对应的模态框都会被同时渲染,最终表现就是模态框加载全量列表数据,甚至可能出现多个模态框叠层的情况 - 按钮点击事件传参错误:定义的
traineeSelectById接收(e, listTrainee)两个参数,但在onClick回调里只传入了listTrainee,导致函数内拿到的e实际是学员数据对象,e.stopPropagation()执行时会直接抛出类型错误,根本没有运行 - 没有单独存储当前选中的单条学员数据,仅靠一个布尔值控制显隐,无法精准匹配要展示的目标记录
修复方案
按以下步骤修改即可解决:
- 新增独立state存储当前选中的学员数据,不要在
map循环内部渲染模态框 - 修正按钮点击事件的传参逻辑,保证事件对象和当前行数据都能正确传入处理函数
- 将模态框组件移到循环外部、和表格同级的位置,全局只渲染一次模态框实例,显隐时传入提前存好的选中项数据
修正后代码
状态定义部分
// 新增选中学员数据的state,初始值为null const [selectedTrainee, setSelectedTrainee] = useState(null); const [isModalTraineeDetailsVisible, setModalTraineeDetailsVisible] = useState(false);
选中处理函数
const traineeSelectById = (e, listTrainee) => { e.stopPropagation(); // 存储当前点击的学员数据 setSelectedTrainee(listTrainee); setModalTraineeDetailsVisible(true); }
表格渲染+模态框部分
// map遍历只渲染表格行和按钮,不在循环内写模态框 listTraineeData.map((listTrainee) => ( <StyledTableRow key={listTrainee.id}> <StyledTableCell>{listTrainee.first_name}</StyledTableCell> <StyledTableCell>{listTrainee.last_name}</StyledTableCell> <StyledTableCell>{listTrainee.num_soci}</StyledTableCell> <StyledTableCell>{listTrainee.addresse1}</StyledTableCell> <StyledTableCell>{listTrainee.active}</StyledTableCell> <StyledTableCell> <Button variant="contained" size="small" // 修正传参,同时传入事件对象e和当前行数据 onClick={(e) => traineeSelectById(e, listTrainee)} > Details modal </Button> </StyledTableCell> </StyledTableRow> )) // 模态框移到循环外,和表格同级,全局只渲染一次 {isModalTraineeDetailsVisible && selectedTrainee ? ( <ModalTraineeDetails data={selectedTrainee} onClose={() => { setModalTraineeDetailsVisible(false); // 关闭时清空选中数据,避免下次打开残留旧数据 setSelectedTrainee(null); }} > <h2>Modal Details Trainee</h2> </ModalTraineeDetails> ) : null}
注意事项
- 所有列表触发单条详情的弹窗/模态框场景,都不要把弹窗放在循环内渲染,单实例+选中项数据的写法性能更好,也能从根源避免数据错乱、多实例叠层问题
- 写事件传参时注意参数顺序和数量,打开浏览器控制台就能看到之前
stopPropagation的执行报错,这类语法问题优先查控制台报错能省很多时间
内容的提问来源于stack exchange,提问作者Rhay
相关产品推荐
相关产品推荐

