From 96c6b780cec5f61d292dd9dd22ae9431e8cb7ecb Mon Sep 17 00:00:00 2001 From: minsung Date: Mon, 12 Oct 2026 17:53:33 +0900 Subject: [PATCH] fix: drop StrictMode to stop double-mounting Viewer2D MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Viewer2D (ported unchanged) has no dispose/teardown API — it attaches permanent window listeners and starts its own rAF render loop in the constructor. React StrictMode's dev-only mount→unmount→remount cycle was constructing it twice into the same container with no way to tear the first instance down, leaving two overlapping canvases and broken rendering (load reported success but nothing appeared on screen). Also defensively clear the container's children before construction so a future remount (e.g. Fast Refresh) can't repeat this. Refs #1 --- src/hooks/useDwgViewer.ts | 10 ++++++++-- src/main.tsx | 12 ++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/hooks/useDwgViewer.ts b/src/hooks/useDwgViewer.ts index cad2d86..d4bf336 100644 --- a/src/hooks/useDwgViewer.ts +++ b/src/hooks/useDwgViewer.ts @@ -78,8 +78,14 @@ export function useDwgViewer() { // mount Viewer2D once useEffect(() => { - if (!containerRef.current) return; - const viewer = new Viewer2D(containerRef.current); + const container = containerRef.current; + if (!container) return; + // Viewer2D has no dispose/teardown API (permanent window/canvas + // listeners, its own rAF loop) — defensively clear any leftover canvas + // from a prior construction (e.g. a dev Fast Refresh remount) so it + // never stacks two live WebGL contexts in the same container. + container.replaceChildren(); + const viewer = new Viewer2D(container); viewerRef.current = viewer; viewer.setTheme(true); viewer.onSelect((entity) => setSelectedEntity(entity)); diff --git a/src/main.tsx b/src/main.tsx index dfacde0..2bf1b15 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,10 +1,10 @@ -import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import App from './App'; import './index.css'; -createRoot(document.getElementById('root')!).render( - - - , -); +// No : Viewer2D (ported unchanged from the vanilla app) has no +// dispose/teardown API and attaches permanent window/canvas listeners in its +// constructor. StrictMode's dev-only mount→unmount→remount double-invoke +// would construct it twice into the same container with no way to tear the +// first instance down, leaving two overlapping WebGL canvases. +createRoot(document.getElementById('root')!).render();