From d901543abaa897a9a0add67fb508d44883d5bac6 Mon Sep 17 00:00:00 2001 From: Autumn-27 <53844290+Autumn-27@users.noreply.github.com> Date: Tue, 18 Aug 2026 09:15:42 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=A6=86=E7=9B=96?= =?UTF-8?q?=E5=9B=BE=E8=B0=B1=E5=8D=B8=E8=BD=BD=E7=AB=9E=E6=80=81=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=9A=84=20g6=20=E5=B4=A9=E6=BA=83(getTransformInstan?= =?UTF-8?q?ce)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit d3-force 力导向布局是异步多帧模拟。布局未跑完就切走图谱标签→组件卸载 graph.destroy() 把 context 清空,飞行中的布局落地时 transformDataAfterLayout 读 context.transform.getTransformInstance() → undefined 崩溃。 - applyData 渲染前判 graph.destroyed;render() 挂 .catch 吞掉 teardown 竞态的 拒绝(已销毁静默,未销毁仍打日志),不再冒泡成运行时错误。 - 卸载先 stopLayout() 再 destroy(),缩短竞态窗口。 --- .../tasks/detail/_tabs/coverage-graph-tab.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/web/src/app/(main)/function/tasks/detail/_tabs/coverage-graph-tab.tsx b/web/src/app/(main)/function/tasks/detail/_tabs/coverage-graph-tab.tsx index 0974489..14201fe 100644 --- a/web/src/app/(main)/function/tasks/detail/_tabs/coverage-graph-tab.tsx +++ b/web/src/app/(main)/function/tasks/detail/_tabs/coverage-graph-tab.tsx @@ -507,9 +507,14 @@ function GraphInner({ taskId }: { taskId: string }) { const applyData = React.useCallback(() => { const graph = graphRef.current; - if (!graph) return; + if (!graph || graph.destroyed) return; graph.setData(gDataRef.current); - void graph.render(); + // render() 异步跑 d3-force 布局;若组件在布局落地前被卸载/销毁,g6 会在已清空的 + // context 上访问 transform 抛错(见 runtime/layout transformDataAfterLayout)。这是纯 + // teardown 竞态,吞掉它,不影响功能;真正的渲染错误(图未销毁)仍打日志。 + void graph.render().catch((err) => { + if (!graph.destroyed) console.error("[coverage-graph] render:", err); + }); }, []); // 建图(一次)。动态 import 避开 SSR/静态导出期的 window 依赖。 @@ -579,6 +584,12 @@ function GraphInner({ taskId }: { taskId: string }) { })(); return () => { destroyed = true; + // 先停布局再销毁:尽量缩短"布局在飞、context 被清空"的竞态窗口。 + try { + graph?.stopLayout(); + } catch { + /* 图可能尚未建成或已无布局上下文 */ + } graph?.destroy(); graphRef.current = null; };