diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 3022c5a1..a7d8fd4b 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -107,6 +107,16 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla const [pdfAnalyzing, setPdfAnalyzing] = useState(false) const { setIsGlobalLoading } = useContext(QcastContext) const pdfInputRef = useRef(null) + // 진행 중인 PDF 분석 요청 추적 — 언마운트(라우팅 이탈) 시 abort 하고, 늦게 도착한 결과가 + // 이미 비워진 canvas 에 적용되거나 이전 플랜으로 저장되는 것을 차단한다. + const pdfRunRef = useRef(null) + + useEffect(() => { + return () => { + pdfRunRef.current?.controller?.abort() + pdfRunRef.current = null + } + }, []) /** * 치수 입력방법(복시도입력/실측값입력/도면 파일 업로드) */ @@ -165,6 +175,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla setPdfAnalyzing(true) setIsGlobalLoading(true) const controller = new AbortController() + pdfRunRef.current = { controller } const timeoutId = setTimeout(() => controller.abort(), PDF_ANALYZE_TIMEOUT_MS) let response = null @@ -188,6 +199,11 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla setIsGlobalLoading(false) } + // 언마운트로 abort 됐거나 다른 실행으로 대체된 경우 — 늦은 결과를 적용하거나 알림을 띄우지 않는다. + if (pdfRunRef.current?.controller !== controller) { + return false + } + // alert/confirm 은 스피너 해제 후 표시한다(스피너 z-index 가 alert 보다 높아 가려지는 것 방지). if (errorKey) { swalFire({ text: getMessage(errorKey), type: 'alert' }) @@ -216,6 +232,11 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla if (!proceed) return false } + // 저신뢰 confirm 대기 중 언마운트된 경우까지 커버하는 최종 가드 + if (pdfRunRef.current?.controller !== controller) { + return false + } + const applied = await applyOuterline(payload.outerline, { unit: payload.unit || 'mm' }) if (!applied) { swalFire({ text: getMessage('pdf.import.error.apply'), type: 'alert' })