mirror of
https://github.com/penpot/penpot.git
synced 2026-09-13 15:38:38 +00:00
⚡ Reduce allocation on layers-tree component
This commit is contained in:
parent
e2576d049a
commit
41f2877801
@ -183,9 +183,6 @@
|
|||||||
[id]
|
[id]
|
||||||
(l/derived #(contains? % id) selected-shapes))
|
(l/derived #(contains? % id) selected-shapes))
|
||||||
|
|
||||||
(def highlighted-shapes
|
|
||||||
(l/derived :highlighted workspace-local))
|
|
||||||
|
|
||||||
(def export-in-progress?
|
(def export-in-progress?
|
||||||
(l/derived :export-in-progress? export))
|
(l/derived :export-in-progress? export))
|
||||||
|
|
||||||
|
|||||||
@ -31,31 +31,47 @@
|
|||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[goog.events :as events]
|
[goog.events :as events]
|
||||||
|
[okulary.core :as l]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(def ^:private highlighted-shapes-ref
|
||||||
|
(l/derived (fn [local]
|
||||||
|
(-> local
|
||||||
|
(get :highlighted)
|
||||||
|
(not-empty)))
|
||||||
|
refs/workspace-local))
|
||||||
|
|
||||||
|
(defn use-selected-shapes
|
||||||
|
"A convencience hook wrapper for get selected shapes"
|
||||||
|
[]
|
||||||
|
(let [selected (mf/deref refs/selected-shapes)]
|
||||||
|
(hooks/use-equal-memo selected)))
|
||||||
|
|
||||||
;; This components is a piece for sharding equality check between top
|
;; This components is a piece for sharding equality check between top
|
||||||
;; level frames and try to avoid rerender frames that are does not
|
;; level frames and try to avoid rerender frames that are does not
|
||||||
;; affected by the selected set.
|
;; affected by the selected set.
|
||||||
(mf/defc frame-wrapper*
|
(mf/defc frame-wrapper*
|
||||||
[{:keys [selected] :as props}]
|
[{:keys [selected] :as props}]
|
||||||
(let [pending-selected (mf/use-var selected)
|
(let [pending-selected-ref
|
||||||
current-selected (mf/use-state selected)
|
(mf/use-ref selected)
|
||||||
props (mf/spread-object props {:selected @current-selected})
|
|
||||||
|
current-selected
|
||||||
|
(mf/use-state selected)
|
||||||
|
|
||||||
|
props
|
||||||
|
(mf/spread-object props {:selected @current-selected})
|
||||||
|
|
||||||
set-selected
|
set-selected
|
||||||
(mf/use-memo
|
(mf/with-memo []
|
||||||
(fn []
|
(throttle-fn 50 #(when-let [pending-selected (mf/ref-val pending-selected-ref)]
|
||||||
(throttle-fn
|
(reset! current-selected pending-selected))))]
|
||||||
50
|
|
||||||
#(when-let [pending-selected @pending-selected]
|
|
||||||
(reset! current-selected pending-selected)))))]
|
|
||||||
|
|
||||||
(mf/with-effect [selected set-selected]
|
(mf/with-effect [selected set-selected]
|
||||||
(reset! pending-selected selected)
|
(mf/set-ref-val! pending-selected-ref selected)
|
||||||
(set-selected)
|
(^function set-selected)
|
||||||
(fn []
|
(fn []
|
||||||
(reset! pending-selected nil)
|
(mf/set-ref-val! pending-selected-ref nil)
|
||||||
#(rx/dispose! set-selected)))
|
(rx/dispose! set-selected)))
|
||||||
|
|
||||||
[:> layer-item* props]))
|
[:> layer-item* props]))
|
||||||
|
|
||||||
@ -63,38 +79,63 @@
|
|||||||
{::mf/wrap [mf/memo #(mf/throttle % 200)]
|
{::mf/wrap [mf/memo #(mf/throttle % 200)]
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[{:keys [objects is-filtered parent-size] :as props}]
|
[{:keys [objects is-filtered parent-size] :as props}]
|
||||||
(let [selected (mf/deref refs/selected-shapes)
|
(let [selected (use-selected-shapes)
|
||||||
selected (hooks/use-equal-memo selected)
|
highlighted (mf/deref highlighted-shapes-ref)
|
||||||
highlighted (mf/deref refs/highlighted-shapes)
|
root (get objects uuid/zero)
|
||||||
highlighted (hooks/use-equal-memo highlighted)
|
|
||||||
root (get objects uuid/zero)]
|
shapes (get root :shapes)
|
||||||
|
shapes (mf/with-memo [shapes objects]
|
||||||
|
(loop [counter 0
|
||||||
|
shapes (seq shapes)
|
||||||
|
result (list)]
|
||||||
|
|
||||||
|
(if-let [id (first shapes)]
|
||||||
|
(if-let [obj (get objects id)]
|
||||||
|
(do
|
||||||
|
;; NOTE: this is a bit hacky, but reduces substantially
|
||||||
|
;; the allocation; If we use enumeration, we allocate
|
||||||
|
;; new sequence and add one iteration on each render,
|
||||||
|
;; independently if objects are changed or not. If we
|
||||||
|
;; store counter on metadata, we still need to create a
|
||||||
|
;; new allocation for each shape; with this method we
|
||||||
|
;; bypass this by mutating a private property on the
|
||||||
|
;; object removing extra allocation and extra iteration
|
||||||
|
;; on every request.
|
||||||
|
(unchecked-set obj "__$__counter" counter)
|
||||||
|
(recur (inc counter)
|
||||||
|
(rest shapes)
|
||||||
|
(conj result obj)))
|
||||||
|
(recur (inc counter)
|
||||||
|
(rest shapes)
|
||||||
|
result))
|
||||||
|
result)))]
|
||||||
|
|
||||||
[:div {:class (stl/css :element-list) :data-testid "layer-item"}
|
[:div {:class (stl/css :element-list) :data-testid "layer-item"}
|
||||||
[:> hooks/sortable-container* {}
|
[:> hooks/sortable-container* {}
|
||||||
(for [[index id] (reverse (d/enumerate (:shapes root)))]
|
(for [obj shapes]
|
||||||
(when-let [obj (get objects id)]
|
(if (cfh/frame-shape? obj)
|
||||||
(if (cfh/frame-shape? obj)
|
[:> frame-wrapper*
|
||||||
[:> frame-wrapper*
|
{:item obj
|
||||||
{:item obj
|
:selected selected
|
||||||
:selected selected
|
:highlighted highlighted
|
||||||
:highlighted highlighted
|
:index (unchecked-get obj "__$__counter")
|
||||||
:index index
|
:objects objects
|
||||||
:objects objects
|
:key (dm/str (get obj :id))
|
||||||
:key id
|
:is-sortable true
|
||||||
:is-sortable true
|
:is-filtered is-filtered
|
||||||
:is-filtered is-filtered
|
:parent-size parent-size
|
||||||
:parent-size parent-size
|
:depth -1}]
|
||||||
:depth -1}]
|
[:> layer-item*
|
||||||
[:> layer-item*
|
{:item obj
|
||||||
{:item obj
|
:selected selected
|
||||||
:selected selected
|
:highlighted highlighted
|
||||||
:highlighted highlighted
|
:index (unchecked-get obj "__$__counter")
|
||||||
:index index
|
:objects objects
|
||||||
:objects objects
|
:key (dm/str (get obj :id))
|
||||||
:key id
|
:is-sortable true
|
||||||
:is-sortable true
|
:is-filtered is-filtered
|
||||||
:is-filtered is-filtered
|
:depth -1
|
||||||
:depth -1
|
:parent-size parent-size}]))]]))
|
||||||
:parent-size parent-size}])))]]))
|
|
||||||
|
|
||||||
(mf/defc filters-tree
|
(mf/defc filters-tree
|
||||||
{::mf/wrap [mf/memo #(mf/throttle % 200)]
|
{::mf/wrap [mf/memo #(mf/throttle % 200)]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user