diff --git a/packages/element/src/store.ts b/packages/element/src/store.ts index ffe9089715..74284ea1c3 100644 --- a/packages/element/src/store.ts +++ b/packages/element/src/store.ts @@ -68,6 +68,8 @@ type MicroActionsQueue = (() => void)[]; * Store which captures the observed changes and emits them as `StoreIncrement` events. */ export class Store { + // internally used by history + public readonly onDurableIncrementEmitter = new Emitter<[DurableIncrement]>(); public readonly onStoreIncrementEmitter = new Emitter< [DurableIncrement | EphemeralIncrement] >(); @@ -265,6 +267,7 @@ export class Store { const increment = new DurableIncrement(change, storeDelta); // Notify listeners with the increment + this.onDurableIncrementEmitter.trigger(increment); this.onStoreIncrementEmitter.trigger(increment); } } @@ -325,6 +328,17 @@ export class Store { appState: AppState | ObservedAppState | undefined, ) { const macroAction = this.getScheduledMacroAction(); + + // perf. optimisation, since "EVENTUALLY" does not update the snapshot, + // so if nobody is listening for increments, we don't need to even clone the snapshot + // as it's only needed for `StoreChange` computation inside `EphemeralIncrement` + if ( + macroAction === CaptureUpdateAction.EVENTUALLY && + !this.onStoreIncrementEmitter.subscribers.length + ) { + return; + } + const nextSnapshot = this.maybeCloneSnapshot( macroAction, elements, diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 9dc8b71082..7f958a51da 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -2547,14 +2547,19 @@ class App extends React.Component { }); } - this.store.onStoreIncrementEmitter.on((increment) => { - if (StoreIncrement.isDurable(increment)) { - this.history.record(increment.delta); - } - - this.props.onIncrement?.(increment); + this.store.onDurableIncrementEmitter.on((increment) => { + this.history.record(increment.delta); }); + const { onIncrement } = this.props; + + // per. optimmisation, only subscribe if there is the `onIncrement` prop registered, to avoid unnecessary computation + if (onIncrement) { + this.store.onStoreIncrementEmitter.on((increment) => { + onIncrement(increment); + }); + } + this.scene.onUpdate(this.triggerRender); this.addEventListeners(); @@ -2614,6 +2619,7 @@ class App extends React.Component { this.eraserTrail.stop(); this.onChangeEmitter.clear(); this.store.onStoreIncrementEmitter.clear(); + this.store.onDurableIncrementEmitter.clear(); ShapeCache.destroy(); SnapCache.destroy(); clearTimeout(touchTimeout);