From 056dda272057bb25cd209ad0da6d330f2dd2ad47 Mon Sep 17 00:00:00 2001 From: Vorflux AI Date: Sat, 28 Mar 2026 08:16:21 +0000 Subject: [PATCH] fix: memoize useGraphTheme return value to prevent cascading re-renders When colorOverrides were provided, useGraphTheme returned a new object on every render, breaking downstream useMemo dependencies and causing the d3 simulation to re-update on every frame. Now uses useMemo with a stable serialization key for the overrides object. --- .../memory-graph/src/hooks/use-graph-theme.ts | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/memory-graph/src/hooks/use-graph-theme.ts b/packages/memory-graph/src/hooks/use-graph-theme.ts index b495189d..f045830a 100644 --- a/packages/memory-graph/src/hooks/use-graph-theme.ts +++ b/packages/memory-graph/src/hooks/use-graph-theme.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react" +import { useEffect, useMemo, useState } from "react" import type { GraphThemeColors } from "../types" import { DEFAULT_COLORS } from "../constants" @@ -102,9 +102,20 @@ export function useGraphTheme( } }, []) - // Apply overrides if provided - if (overrides) { - return { ...colors, ...overrides } - } - return colors + // Serialize overrides to a stable string key so useMemo only recomputes + // when the actual override values change, not on every render. + const overrideKey = overrides + ? Object.entries(overrides) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([k, v]) => `${k}:${v}`) + .join(",") + : "" + + const merged = useMemo( + () => (overrides ? { ...colors, ...overrides } : colors), + // biome-ignore lint/correctness/useExhaustiveDependencies: overrideKey tracks overrides by value + [colors, overrideKey], + ) + + return merged }