From ef0ce15bb53a9bdfdfecf090324e317d8c2f9b33 Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Sat, 4 Jul 2026 15:37:54 +0200 Subject: [PATCH] perf(view): reduce shell rerenders --- view/App.tsx | 76 +++++++++------ view/CanvasViewport.tsx | 57 ++++++++++- view/GenerateSheet.tsx | 17 ++-- view/LayersSheet.tsx | 43 +++++++-- view/bottom-controls/GenerateControls.tsx | 112 ---------------------- view/canvas/brush.ts | 18 ++-- view/generate/runGenerate.ts | 2 +- view/useAppState.test.ts | 68 +++++++++++++ view/useAppState.ts | 101 ++++++++++++++++++- 9 files changed, 321 insertions(+), 173 deletions(-) create mode 100644 view/useAppState.test.ts diff --git a/view/App.tsx b/view/App.tsx index 2405d9d..d863302 100644 --- a/view/App.tsx +++ b/view/App.tsx @@ -10,9 +10,10 @@ import { LayersSheet } from "./LayersSheet"; import { ShortcutsDisplay } from "./ShortcutsDisplay"; import { ToolOverlay } from "./ToolOverlay"; import { resolveTransformTargetBounds, selectedTransformTarget } from "@editor/transform-targets"; +import type { AppState } from "@editor/state"; import type { ToolId } from "@editor/tools"; import { handleDeleteSelectionKey, handleHistoryKey, handleToolKey, keybindEventFromKeyboardEvent } from "@input/index"; -import { useAppState } from "./useAppState"; +import { shallowEqual, useAppState } from "./useAppState"; import { downloadArtboardPng } from "./exportArtboardPng"; import { useImageImport } from "./useImageImport"; import { useViewportActivityIsland } from "./useViewportActivityIsland"; @@ -23,14 +24,15 @@ export type AppProps = { }; export function App({ app }: AppProps) { - const state = useAppState(app.store); - const viewportActivityIsland = useViewportActivityIsland(state.editor.viewport); + const shellState = useAppState(app.store, selectAppShellState, shallowEqual); + const { document, selection, viewport, tools, transformSession, maskEdit } = shellState; + const viewportActivityIsland = useViewportActivityIsland(viewport); const imageImport = useImageImport(app.store); const [layersOpen, setLayersOpen] = useState(false); const [generateOpen, setGenerateOpen] = useState(false); const previousGenerateTool = useRef("select"); - const transformTarget = state.editor.transformSession?.target ?? selectedTransformTarget(state.document, state.editor.selection); - const activeArtboard = state.document.artboards.find((artboard) => artboard.id === state.editor.selection.artboardId) ?? state.document.artboards[0]; + const transformTarget = transformSession?.target ?? selectedTransformTarget(document, selection); + const activeArtboard = document.artboards.find((artboard) => artboard.id === selection.artboardId) ?? document.artboards[0]; const openGenerate = useCallback(() => { const activeTool = app.store.getState().editor.tools.activeTool; @@ -108,8 +110,8 @@ export function App({ app }: AppProps) { window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [app.store, closeGenerate, toggleGenerate]); - const transformBounds = transformTarget ? resolveTransformTargetBounds(state.document, transformTarget) : undefined; - const brushHint = brushUnavailableHint(state.document, state.editor); + const transformBounds = transformTarget ? resolveTransformTargetBounds(document, transformTarget) : undefined; + const brushHint = brushUnavailableHint(document, { selection, tools, maskEdit }); return (
@@ -122,7 +124,7 @@ export function App({ app }: AppProps) { -