From b8ea606f9247829f1b2b39a516494c4bd6932e2c Mon Sep 17 00:00:00 2001
From: ruinivist <179396038+ruinivist@users.noreply.github.com>
Date: Fri, 5 Jun 2026 08:11:35 +0000
Subject: [PATCH] perf: prevent expensive excalidraw re-renders on keystroke
Wraps `onExcalidrawAPI` in `useCallback` to prevent the heavy Excalidraw canvas component from re-rendering on every keystroke when typing in the code block editor.
Wraps `DrawingSidebar` in `memo` and utilizes stable callbacks passed from `App.tsx` instead of inline functions to prevent unnecessary list re-renders.
---
.jules/bolt.md | 4 ++++
src/client/App.tsx | 16 +++++++------
src/client/components/DrawingSidebar.tsx | 29 ++++++++++++------------
3 files changed, 28 insertions(+), 21 deletions(-)
create mode 100644 .jules/bolt.md
diff --git a/.jules/bolt.md b/.jules/bolt.md
new file mode 100644
index 0000000..89d7f05
--- /dev/null
+++ b/.jules/bolt.md
@@ -0,0 +1,4 @@
+## 2024-06-25 - Excalidraw Memoization
+
+**Learning:** The `@excalidraw/excalidraw` package's `Excalidraw` component is exceptionally expensive to re-render. Even though `EditorCanvas` was wrapped in `React.memo`, passing an inline arrow function to `onExcalidrawAPI` in the parent `App` broke memoization, causing severe input lag when typing in completely independent UI elements like the codeblock editor sidebar due to the entire canvas re-rendering.
+**Action:** When passing callbacks to heavy third-party components like Excalidraw, always wrap them in `useCallback` hook to preserve their prop stability and maintain `React.memo` benefits, preventing disastrous performance regressions on typing/input.
diff --git a/src/client/App.tsx b/src/client/App.tsx
index 33ddb41..2035bde 100644
--- a/src/client/App.tsx
+++ b/src/client/App.tsx
@@ -307,6 +307,10 @@ function PrivateApp() {
[],
);
+ const handleExcalidrawAPI = useCallback((api: ExcalidrawImperativeAPI) => {
+ excalidrawApiRef.current = api;
+ }, []);
+
return (