This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-10-08
Channels
- # announcements (20)
- # aws (16)
- # babashka (63)
- # beginners (75)
- # calva (35)
- # cider (2)
- # clj-commons (5)
- # clj-kondo (2)
- # cljs-dev (1)
- # clojure (90)
- # clojure-australia (3)
- # clojure-europe (16)
- # clojure-france (1)
- # clojure-nl (4)
- # clojure-uk (5)
- # clojurescript (7)
- # data-science (2)
- # datahike (1)
- # datomic (39)
- # emacs (31)
- # events (2)
- # figwheel-main (1)
- # fulcro (15)
- # gratitude (8)
- # helix (17)
- # holy-lambda (1)
- # introduce-yourself (1)
- # jobs (3)
- # kaocha (2)
- # liquid (1)
- # malli (1)
- # nrepl (2)
- # other-languages (1)
- # portal (76)
- # react (19)
- # reagent (9)
- # remote-jobs (1)
- # rewrite-clj (9)
- # shadow-cljs (31)
- # tools-deps (5)
- # xtdb (11)
yeah, the default behavior of React (and thus Helix) is to rerender even if it's given similar data
I would just profile your app and memoize the components that are slow, and see if that helps
K, will do thanks @lilactown
Related to that, do you generally pass things like ids as props or maps/objects? One of my go to optimizations is to do stuff like select keys on sequences and just pass ids and basic data types as props. Then in my child components use hooks with those props to hydrate more complete objects. More of a general React question I guess but just curious about your thoughts and if helix favors a particular strategy
Sorry, one more question. When I use {:wrap [(helix.core/memo)]}
the same issue happens even with basic props of a few int ids. I have to use {:wrap [(helix.core/memo =)]}
to have it act as expected which makes me think I'm not understanding the basic memo if the props maps are always referentially different...
a couple things I think will help:
1. helix.core/memo
has a bug in it where it doesn't correctly default compare props when used with factory functions
2. React memoization by default requires you to think about reference equality, not value equality
I'm actually not sure what helix.core/memo
's default behavior should be with factory functions
but while I'm thinking about that, you can write your own comparison function, like
(defn identical-factory-props?
[prev cur]
(let [prev-props (:helix/props prev)
cur-props (:helix/props cur)]
(identical? prev-props cur-props)))
which will check to see if the maps you pass in are identical?
.or, if you are constructing a new map every render but want to check to see if each value within it is identical:
(defn factory-props-kvs-identical?
[prev cur]
(let [prev-props (:helix/props prev)
cur-props (:helix/props cur)]
(and (= (count prev-props) (count cur-props))
(every?
#(identical? (get prev-props %) (get cur-props %))
(keys cur-props)))))
> Related to that, do you generally pass things like ids as props or maps/objects? One of my go to optimizations is to do stuff like select keys on sequences and just pass ids and basic data types as props. Then in my child components use hooks with those props to hydrate more complete objects. More of a general React question I guess but just curious about your thoughts and if helix favors a particular strategy This can work. I'm not sure yet how I would compare them but another option is to memoize the expensive computations themselves. This means that you'll still render the components on each change, but the expensive parts will only be run if the data the parts care about change
it depends on if you're storing your data outside the react tree (which it sounds like you are, if you're able to hydrate them via ID and listen to changes) or inside the react tree
it's the difference between computing the expensive thing every render, and relying on subscription to external sources:
(defnc my-component
[{:keys [entity-id]}]
(let [entity (subscribe [:entity entity-id])
derived-info (expensive-to-compute (:name entity) (:foo entity))]
,,,))
or only computing the expensive thing when the things in entity we care about have changed:
(defnc my-component
[{:keys [entity]}]
(let [derived-info (hooks/use-memo
[(:name entity) (:foo entity)]
(expensive-to-compute (:name entity) (:foo entity)))]
,,,))
which creating new elements can be included in this, if rendering some child component is really expensive then you can memoize it in its parent too....
(defnc my-component
[{:keys [entity]}]
(d/div
(hooks/use-memo
[(:name entity) (:foo entity)]
($ expensive-component-to-render
{:name (:name entity)
:foo (:foo entity)}))))