This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-11-07
Channels
- # announcements (11)
- # babashka (29)
- # beginners (70)
- # biff (13)
- # calva (1)
- # clojure (24)
- # clojure-europe (125)
- # clojure-nl (1)
- # clojure-norway (7)
- # clojure-portugal (2)
- # clojure-uk (3)
- # clojurescript (9)
- # core-async (29)
- # cursive (4)
- # emacs (10)
- # etaoin (14)
- # events (3)
- # fulcro (10)
- # funcool (4)
- # helix (1)
- # honeysql (12)
- # introduce-yourself (1)
- # jobs (2)
- # juxt (2)
- # lsp (1)
- # off-topic (17)
- # polylith (58)
- # portal (20)
- # remote-jobs (2)
- # shadow-cljs (2)
- # squint (4)
- # tools-deps (9)
I have a question.. something works I just want to know HOW OR WHY I have a table with a component called "sortable-table-header" which I sent the data to so it sorts by columns... Here is the code for the sortable-table-header:
(defn sortable-table-header [] ;;with let (CHECK)
(let [show-arrow? (r/atom nil)
sort-direction (r/atom :asc)]
(fn [{:keys [data unfiltered-data columns]}]
[table-head {:class (table-head-style)}
[table-row {:id @sort-direction}
(map-indexed (fn [index column-title]
[table-cell {:class (table-header-1-style)} column-title
[table-sort-label {:active (= @show-arrow? column-title)
:direction @sort-direction
:onClick #(do (sort-table-by (aget (into-array (:values columns)) index) data @sort-direction)
(reset! sort-direction (if (= @sort-direction :asc) :desc :asc))
(reset! show-arrow? column-title))}]
(when (= @show-arrow? column-title) [:span {:class (close-icon-span-style)
:onClick #(do (reset! data @unfiltered-data)
(reset! show-arrow? nil)
(reset! sort-direction :asc))} [close-icon {:size "18px"}]])]) (:names columns))]])))
In line 6, if I don't add "@sort-direction" as id, it will not show the value inside the map. It will not render it, I add the value as an id because that is the only way I can "remind" the map about its value. If I also add it in a println before the map it also works.
My question is WHY?? Why does it forget to render it unless I add it as an id or in a println. Is there no other way to make it work too?
THANKS.Your help would be much appreciated, since I asked 2 clojure experts and they didn't know why reallyKinda hard to answer for sure without knowing what table-row
and other table-related components are.
But two things:
• Don't deref ratoms inside a lazy collection that you don't realize yourself, like with that map-indexed
. There should be a warning about it or something related in the JS console
• When you deref a ratom within a view, it gets registered by Reagent to trigger subsequent re-renders. It doesn't matter how that value is used - all that matters is that deref. So that's why (println @sort-direction)
works, and you can even write it as just @sort-direction
, without ever using that value.
Also, (aget (into-array (:values columns)) index)
looks weird.
Unless (:values columns)
is a lazy collection that you for some reason must realize in full at this specific location, I would simply write it as (nth (:values columns) index)
.
Another thing - don't use reset!
with @
of the same atom. Doesn't matter here, matters greatly in CLJ. Better to stick to a proper solution that works everywhere - namely, swap!
.
Finally, when you have two values that you always or almost always change and read together, like with those show-arrow?
and sort-direction
, it might make sense to combine them into a single atom that contains a map of those two values. IIRC it has bitten me a few times with rather complex components where multiple subsequent calls to reset!
would trigger multiple re-renders where just one would suffice.
Okay thanks. -So got the {:id @sort-direction} there is no other way han putting it in id or println right? -I changed the (aget ...) -How can I use swap! for instance, i sort-direction has at least 3 different values, I can't right? If you mean for showsort-direction, how do I use swap where it changes between :asc and :desc? I know it can be done if its a boolean for example Thanks
> there is no other way han putting it in id or println right? As I said, you can just deref it, without using the value at all. As in:
(fn [{:keys [data unfiltered-data columns]}]
@sort-direction
[table-head ...])
But a much better solution would be to realize map-indexed
. E.g. like here:
[table-row {}
(into []
(map-indexed (fn ...))
(:names columns))]
If that doesn't work, try
(into [table-row {}]
(map-indexed (fn ...))
(:names columns))
> How can I use swap!
By replacing this line
(reset! sort-direction (if (= @sort-direction :asc) :desc :asc))
with this one
(swap! sort-direction #(if (= % :asc) :desc :asc))
Is this for Reagent? It looks like you are aiming at a form-2 component, so you could double-check https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md#form-2--a-function-returning-a-function. That section also hints why one usually associates an event key with a (pre-existing) named function: These #() or (fn...) forms make a new function every time React calls to get fresh HTML. You could unclutter your program and also make it work a tiny bit better by factoring those functions out.