Compare commits

..

1 Commits

Author SHA1 Message Date
ruinivist f76534b632 perf: optimize editorcanvas memoization and debounce shiki highlighting 2026-06-04 07:51:05 +00:00
3 changed files with 15 additions and 18 deletions
-4
View File
@@ -1,4 +0,0 @@
## 2024-06-07 - Memoize callbacks passed to Excalidraw
**Learning:** Due to the exceptionally high rendering cost of the `@excalidraw/excalidraw` canvas, always ensure all callbacks passed to it (e.g., `onExcalidrawAPI`) are strictly memoized using `useCallback`. Passing inline functions as props breaks prop stability for `React.memo` and causes severe UI input lag caused by full canvas re-renders when parent states change.
**Action:** When working with `<Excalidraw>` or its wrapper components like `<EditorCanvas>`, always extract inline callback functions (like `onExcalidrawAPI={(api) => { ... }}`) into `useCallback` hooks before passing them down.
-3
View File
@@ -307,9 +307,6 @@ function PrivateApp() {
[], [],
); );
// ⚡ Bolt: Memoize the Excalidraw API callback to prevent EditorCanvas from re-rendering
// Excalidraw has exceptionally high rendering cost, so we must maintain prop stability
// for EditorCanvas's React.memo to avoid severe UI input lag on any parent state change.
const handleExcalidrawAPI = useCallback((api: ExcalidrawImperativeAPI) => { const handleExcalidrawAPI = useCallback((api: ExcalidrawImperativeAPI) => {
excalidrawApiRef.current = api; excalidrawApiRef.current = api;
}, []); }, []);
+15 -11
View File
@@ -30,20 +30,24 @@ function CodeBlockEditor({
useEffect(() => { useEffect(() => {
let cancelled = false; let cancelled = false;
void renderHighlightedCodeBlockHtml(draft.code, draft.language)
.then((nextHtml) => { const timeoutId = setTimeout(() => {
if (!cancelled) { void renderHighlightedCodeBlockHtml(draft.code, draft.language)
setHtml(nextHtml); .then((nextHtml) => {
} if (!cancelled) {
}) setHtml(nextHtml);
.catch(() => { }
if (!cancelled) { })
setHtml(null); .catch(() => {
} if (!cancelled) {
}); setHtml(null);
}
});
}, 100);
return () => { return () => {
cancelled = true; cancelled = true;
clearTimeout(timeoutId);
}; };
}, [draft.code, draft.language]); }, [draft.code, draft.language]);