Fork me on GitHub
#clojurescript
<
2022-11-07
>
M J08:11:24

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 really

p-himik09:11:03

Kinda 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.

p-himik09:11:56

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).

p-himik09:11:32

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.

M J09:11:44

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

p-himik09:11:13

> 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))

p-himik11:11:11

Oh, BTW - such questions should be asked in #C0620C0C8.

M J11:11:34

ok thank you

👍 1
phill10:11:58

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.