Fork me on GitHub
#reagent
<
2023-02-28
>
rickmoynihan17:02:16

I’m playing with reagent and have tried implementing a simple tabs component which receives a specification of tabs to render and manages the display of the appropriate pane, as you’d expect. For the most part it works fine; but I’ve now made the tab labels components, and noticed that they’re not reactively re-rendering.

rickmoynihan17:02:22

The implementation looks like this:

(defn tab-control [{:keys [id label] :as tab-opts}]
  [:<> [:input (assoc tab-opts
                      :type :radio)]
   [:label {:for id} label]])

(defn tabs [{:keys [name default-tab tabs]} tab-panes]
  (let [selected-tab (r/atom default-tab)]
    (fn [{:keys [name default-tab tabs]} tabs-panes]
      (let [tab-controls (vec (cons :span.tab-controls
                                    (mapv (fn [tab-id]
                                            (let [{:keys [label]} (get tab-panes tab-id)]
                                              [tab-control {:id tab-id
                                                            :name name
                                                            :label label
                                                            :value tab-id
                                                            :checked (= tab-id @selected-tab)
                                                            :on-change #(reset! selected-tab tab-id)}]))
                                          tabs)))
            selected-tab-pane (:pane (get tab-panes @selected-tab))]
        [:div.tabs
         tab-controls
         [:div.tab-pane {}
          selected-tab-pane]]))))
and the example usage is:
(let [{:keys [errors appends deletes corrections]} @state]
  [tabs {:default-tab :errors
         :name :change-type
         :tabs [:errors :appends :deletes :corrections]}
   {:errors {:label [:<> "Errors (" (count errors) ")"]
             :pane [:h1 "Errors"]}
    :appends {:label [:<> "Appends"]
              :pane [:h1 "Appends"]}
    :deletes {:label [:<> "Deletes"]
              :pane [:h1 "Deletes"]}
    :corrections {:label [:<> "Corrections"]
                  :pane [:h1 "Corrections"]}}])
and it’s the (count errors) that I’d expect to be re-rendering

p-himik17:02:57

In your tabs component, very carefully compare signatures of the outer and inner functions. Also, I would suggest looking into setting up highlighting unused symbols in your editor - very useful, and not only in similar cases.

rickmoynihan17:02:04

ahh thanks — code blindness, it’s been a long day! I have unused symbol highlighting already… I was just kinda ignoring it because of the false positives with the outermost symbols being shadowed on the inner function

rickmoynihan17:02:55

I was thinking I might replace them with _ but then I’d need to add args-list metadata

p-himik17:02:18

Ah, to avoid those false positives I use stuff like (fn [{#_#_:keys [name default-tab tabs]} ...] ...).

p-himik17:02:38

Of course, that doesn't help with in-editor documentation. :(

p-himik17:02:04

Oh, wait - it actually does help, at least in Cursive.

rickmoynihan17:02:32

I use emacs/cider

p-himik17:02:22

What about {:keys [_name _default-tab _tabs]}?

rickmoynihan17:02:09

lol I actually do that elsewhere… 🙂 I should do that here too! 😩

clojure-spin 2
rickmoynihan17:02:18

I should probably call it a day 🙂

😄 2
rickmoynihan17:02:05

Anyway, thanks for the 🧸ing - it’ll at least mean I can finish for the day without this hanging over me! 🙂

👍 2
🎉 2