From 61e0bb83d091a761d4e8305ac99c486c99ac4f2c Mon Sep 17 00:00:00 2001 From: Are Date: Thu, 30 Jan 2025 14:41:08 +0100 Subject: [PATCH] feat: improve library sidebar performance (#9060) Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com> --- .../excalidraw/components/LibraryMenu.tsx | 64 +++++++++++++------ packages/excalidraw/types.ts | 2 + 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/packages/excalidraw/components/LibraryMenu.tsx b/packages/excalidraw/components/LibraryMenu.tsx index 4b4cccbae7..4b76dfc4a4 100644 --- a/packages/excalidraw/components/LibraryMenu.tsx +++ b/packages/excalidraw/components/LibraryMenu.tsx @@ -1,4 +1,10 @@ -import React, { useState, useCallback, useMemo, useRef } from "react"; +import React, { + useState, + useCallback, + useMemo, + useRef, + useEffect, +} from "react"; import type Library from "../data/library"; import { distributeLibraryItemsOnSquareGrid, @@ -150,27 +156,40 @@ const usePendingElementsMemo = ( appState: UIAppState, elements: readonly NonDeletedExcalidrawElement[], ) => { - const create = () => - getSelectedElements(elements, appState, { - includeBoundTextElement: true, - includeElementsInFrames: true, - }); - const val = useRef(create()); + const create = useCallback( + (appState: UIAppState, elements: readonly NonDeletedExcalidrawElement[]) => + getSelectedElements(elements, appState, { + includeBoundTextElement: true, + includeElementsInFrames: true, + }), + [], + ); + + const val = useRef(create(appState, elements)); const prevAppState = useRef(appState); const prevElements = useRef(elements); - if ( - !isShallowEqual( - appState.selectedElementIds, - prevAppState.current.selectedElementIds, - ) || - !isShallowEqual(elements, prevElements.current) - ) { - val.current = create(); - prevAppState.current = appState; - prevElements.current = elements; - } - return val.current; + const update = useCallback(() => { + if ( + !isShallowEqual( + appState.selectedElementIds, + prevAppState.current.selectedElementIds, + ) || + !isShallowEqual(elements, prevElements.current) + ) { + val.current = create(appState, elements); + prevAppState.current = appState; + prevElements.current = elements; + } + }, [create, appState, elements]); + + return useMemo( + () => ({ + update, + value: val.current, + }), + [update, val], + ); }; /** @@ -181,6 +200,7 @@ export const LibraryMenu = () => { const { library, id, onInsertElements } = useApp(); const appProps = useAppProps(); const appState = useUIAppState(); + const app = useApp(); const setAppState = useExcalidrawSetAppState(); const elements = useExcalidrawElements(); const [selectedItems, setSelectedItems] = useState([]); @@ -203,9 +223,13 @@ export const LibraryMenu = () => { }); }, [setAppState]); + useEffect(() => { + return app.onPointerUpEmitter.on(() => pendingElements.update()); + }, [app, pendingElements]); + return (