# 体位选择与Viewer同步修复文档 ## 问题描述 在使用图像处理页面时,切换到1x1布局后,viewer总是显示第一个图像,而非选中体位对应图像。同时,发现切换体位时会导致无限渲染循环错误。 ### 表现症状 1. 切换到1x1布局时,总是选择第一个图像 2. 体位选择时出现无限渲染循环:"Maximum update depth exceeded" 3. 1x1布局无法正确显示对应选中的体位图像 ## 根本原因分析 ### 1. ViewerContainer.tsx 无限循环问题 - **现象**:renderGrid函数中在渲染期间dispatch状态变化 - **问题**: - useEffect监听selectedBodyPosition和gridLayout,每次变化时调用renderGrid() - renderGrid()中1x1 case内dispatch toggleViewerSelection - dispatch导致组件重新渲染,又触发useEffect → renderGrid() → dispatch → ... - **结果**:无限渲染循环,导致应用卡死 ### 2. Viewer选择逻辑问题 - **现象**:1x1布局硬编码选择allViewerUrls[0] - **问题**:未与selectedBodyPosition关联 - **结果**:切换布局时无法保持选中体位的高亮状态,且不显示对应图像 ### 3. 显示逻辑问题 - **现象**:renderViewers(0, 1) 总是显示图像数组的第一个元素 - **问题**:未利用selectedBodyPosition确定显示的图像索引 - **结果**:1x1布局锁定了第一个图像,无法同步到选中体位 ### 4. 数据流分析 ``` BodyPositionList 点击 → selectedBodyPosition 更新 ↓ ViewerContainer useEffect触发 → renderGrid() → dispatch → 重新渲染 ↓ 无限循环异常 ↓ 布局切换 → 固定选择第一个图像 ``` ## 修复方案 ### 修改1: 移除引发无限循环的useEffect **文件**: `src/pages/view/components/ViewerContainer.tsx` ```typescript // 移除以下useEffect,因为它会导致renderGrid在每次渲染时被调用 // 删除此useEffect以避免循环 ``` **变更点**: - 删除 `useEffect(() => { renderGrid(); }, [selectedBodyPosition, gridLayout])` - 避免在渲染前调用renderGrid导致的循环 ### 修改2: 添加状态检查,避免重复dispatch **文件**: `src/pages/view/components/ViewerContainer.tsx` 在1x1 case中添加状态检查逻辑: ```typescript case '1x1': { // 根据 selectedBodyPosition 找到对应URL let urlToSelect = allViewerUrls[0]; // fallback if (selectedBodyPosition?.sop_instance_uid) { const correspondingUrl = getDcmImageUrl(selectedBodyPosition.sop_instance_uid); const urlIndex = allViewerUrls.indexOf(correspondingUrl); if (urlIndex !== -1) { urlToSelect = allViewerUrls[urlIndex]; } } // 检查当前选中状态,避免重复dispatch导致的无限循环 const currentSelected = selectedViewerUrls[0]; if (currentSelected !== urlToSelect) { if (currentSelected) { dispatch(toggleViewerSelection(currentSelected)); // 取消选中当前 } dispatch(toggleViewerSelection(urlToSelect)); // 选中新的 } // 修改renderViewers调用,根据selectedBodyPosition确定显示的图像索引 let viewerIndex = 0; if (selectedBodyPosition?.sop_instance_uid) { const correspondingUrl = getDcmImageUrl(selectedBodyPosition.sop_instance_uid); const index = imageUrls.indexOf(correspondingUrl); if (index !== -1) { viewerIndex = index; } } return (