This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-30
Channels
- # babashka (46)
- # beginners (234)
- # bristol-clojurians (4)
- # cider (7)
- # clj-kondo (39)
- # cljdoc (8)
- # cljs-dev (10)
- # cljsjs (10)
- # cljsrn (24)
- # clojure (84)
- # clojure-brasil (7)
- # clojure-europe (12)
- # clojure-germany (4)
- # clojure-italy (3)
- # clojure-nl (41)
- # clojure-spec (17)
- # clojure-uk (66)
- # clojurescript (64)
- # conjure (161)
- # cursive (12)
- # data-science (45)
- # datomic (20)
- # devops (11)
- # docker (2)
- # duct (9)
- # events (7)
- # figwheel (1)
- # figwheel-main (20)
- # fulcro (32)
- # graalvm (5)
- # helix (82)
- # jackdaw (9)
- # jobs-discuss (19)
- # kaocha (11)
- # local-first-clojure (1)
- # malli (6)
- # meander (3)
- # nrepl (12)
- # off-topic (2)
- # other-lisps (15)
- # pathom (14)
- # rdf (6)
- # re-frame (8)
- # reactive (1)
- # reagent (5)
- # reitit (4)
- # rum (3)
- # shadow-cljs (77)
- # spacemacs (3)
- # sql (9)
- # test-check (31)
- # tools-deps (13)
- # vim (62)
- # xtdb (18)
Hello all, I have one question about when to use #js
in props using with ($ Compoment {...props...} children)
?
if Component
expects a JS object or array as a prop, then you will need to pass it one
@lilactown so, all the props level 1 and nested?
helix does some special handling for the :style
prop of elements like div
/ span
/ etc.
Like here
(:require ["bizcharts" :refer (Chart Line Point)])
(defnc Graphic []
($ Chart
{:autoFit true
:height 500
:data (into-array [{:year "1990" :value 3}
{:year "1991" :value 6}
{:year "1992" :value 10}])
:scale {:value {:min 0}}}
($ Line {:position "year*value"}))
helix will rewrite
{:autoFit true
:height 500
:data (into-array ,,,)
:scale {:value {:min 0}}}
into
#js {:autoFit true
:height 500
:data (into-array ,,,)
:scale {:value {:min 0}}}
if it expects the value of scale
to be a nested JS obj, you’ll need to make sure you pass in a JS obj
like here (my-component #js {:person #js {:firstName "Miguel" :lastName "Ribeiro"}})
in docs
if it expects data
to be an array of objects, you will need to make sure you pass in an array of objects - not a vector of maps
{:autoFit true
:height 500
:data #js [#js {,,,} ,,,]
:scale #js {:value #js {:min 0}}}
if your component takes CLJS vectors and maps, you wouldn’t want those to become arrays and objects
what is different is the data that they use, js components need js data, cljs components need cljs data
if you write component that doesn't care about what data it gets, you can use it both places
e.g. react-select can be given an array of CLJS maps and a custom :getOptionValue
:getOptionLabel
prop
which is much better than converting all of your data to JS objects, and then converting all back to maps when you get it back from react-select
there’s too many different cases. you are the best person to know what kind of value to pass to your component, not helix
what I found often is that I think I need bean, I use it, and then it turns out there is a simpler way which doesn't require conversion
so as an intermediary hack is very very often used for now, I expect if I get more experience I will use it less
if you’re reading docs for an external React component and it has you pass in objects/arrays, you probably have to pass in objects and arrays
Is there a way to get (helix.hooks/use-effect [foo] ...)
to use cljs.core/=
for checking whether foo changed? I'd like to use an effect that depends on changes to a non-primitive clojure value.
you can use another hook to maintain referential identity if foo
is deep equals but for some reason a different reference
but there are only a few cases where that should be necessary; why can’t you rely on foo
being the same reference to check for equality?
in my case, foo ends up always being the result of another function, which might might get re-run to produce a cljs.core/= value
that would work! i'd have to be careful tho to turn it into a pure function, as it currently dereferences state inside its body
ok, put another way, the function is inside the scope of the defnc
and uses state variables that are in the lexical scope of its body
but then i think i'm back to the same problem where i have to explicitly declare the deps to the memoized function body (and those deps won't be compared by value if they change), am i missing something?
sorry to belabor this, maybe i'm missing some concept. i think what i really want to express is "run this effect whenever the value of foo changes". i like the idea of using a separate effect to track the value of the deps using the value semantics of my choice. maybe i'll just wrap that up into a higher-order use-effect that takes in an extra arg about how values are compared
the idea is that you should try and ensure that your reference changes only if your value changes
and here when you say "reference" you mean like js pointer, not react/useRef (just to clarify)
yeah, things like:
(let [some-static-data {:foo "bar"} ;; bad, recreated every render
some-calculation (use-memo
[some-static-data]
(assoc :foo "baz"))]
(def some-static-data {:foo "bar"}) ;; good - only created once, keeps same reference identity
(let [some-calculation (use-memo
[some-static-data]
(assoc :foo "baz"))]
you want to write your code so that if two values are =
then they are probably identical?
too
using things like use-memo
and use-callback
to avoid re-processing or re-creating the same stuff every render helps a lot here
i'm really just not used to reasoning about whether two values being = implies they are identical?
almost always things are identical?
when they’re =
if you structure things right
the strategy is: • build the initial value once • calculate only when things change if you follow those two rules, then you’ll be golden
there are some cases like e.g. deserializing data from an external source (e.g. localStorage, or an HTTP endpoint), where you can’t tell if the data will be the same until you do a deep comparison like =
in those specific cases, you can use a custom hook to check to see if the two values fails =
and if so, return the new value, otherwise, keep returning the old one and toss the new one away
i see, yeah agree that seems ideal way to get best performance, and i wish i had been building my app with that mindset. alas, i've been cavalier about this stuff and not worried at all about performance so far, and this could be quite a bit of restructuring, but i will think more on it. thank you for these insights!
this discussion could actually have a valuable place in the helix docs, i could try to draft a summary if you'd like. i've found one of the tricky things in general about interop'ing with react from clojure is to understand which kind of value semantics are being applied when