From b15c1e94ae4295bffb218096b284b6c69791e4d1 Mon Sep 17 00:00:00 2001 From: shrimbly Date: Tue, 10 Mar 2026 22:05:04 +1300 Subject: [PATCH] perf: add requestAnimationFrame debouncing to BaseNode ResizeObserver Wrap the ResizeObserver callback in requestAnimationFrame with cancellation to coalesce rapid resize events into one setNodes call per frame. Cleanup cancels any pending RAF on unmount. Co-Authored-By: Claude Opus 4.6 --- src/components/nodes/BaseNode.tsx | 43 +++++++++++++++++++------------ 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/components/nodes/BaseNode.tsx b/src/components/nodes/BaseNode.tsx index ba44b363..bbca1716 100644 --- a/src/components/nodes/BaseNode.tsx +++ b/src/components/nodes/BaseNode.tsx @@ -100,27 +100,36 @@ export function BaseNode({ const panelEl = settingsPanelRef.current; if (!panelEl) return; + let rafId: number | null = null; + const observer = new ResizeObserver((entries) => { - for (const entry of entries) { - const newPanelHeight = entry.contentRect.height; - if (newPanelHeight === 0) continue; - const delta = newPanelHeight - trackedSettingsHeightRef.current; - if (Math.abs(delta) < 2) continue; // Ignore sub-pixel changes - - trackedSettingsHeightRef.current = newPanelHeight; - setNodes((nodes) => - nodes.map((node) => { - if (node.id !== id) return node; - const currentHeight = getNodeDimension(node, "height"); - const newHeight = Math.max(minHeight, currentHeight + delta); - return applyNodeDimensions(node, getNodeDimension(node, "width"), newHeight); - }) - ); - } + if (rafId !== null) cancelAnimationFrame(rafId); + rafId = requestAnimationFrame(() => { + rafId = null; + for (const entry of entries) { + const newPanelHeight = entry.contentRect.height; + if (newPanelHeight === 0) continue; + const delta = newPanelHeight - trackedSettingsHeightRef.current; + if (Math.abs(delta) < 2) continue; // Ignore sub-pixel changes + + trackedSettingsHeightRef.current = newPanelHeight; + setNodes((nodes) => + nodes.map((node) => { + if (node.id !== id) return node; + const currentHeight = getNodeDimension(node, "height"); + const newHeight = Math.max(minHeight, currentHeight + delta); + return applyNodeDimensions(node, getNodeDimension(node, "width"), newHeight); + }) + ); + } + }); }); observer.observe(panelEl); - return () => observer.disconnect(); + return () => { + if (rafId !== null) cancelAnimationFrame(rafId); + observer.disconnect(); + }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [settingsExpanded, settingsPanel]);