hyperfiddle

euccastro 2025-04-13T10:00:09.566299Z

If I want to swap! an atom on a button click, all client side and with no need for error handling, am I still supposed to use e/Token? Or is it OK to just do the swap! in the "event transforming function" passed to dom/On?

euccastro 2025-04-13T10:27:53.692409Z

And is it safe to do in the context of a virtual scroll? For example, the following seems to work fine. Am I setting myself up for trouble?

(ns electric-starter-app.main
  (:require #?(:clj [electric-starter-app.debug :refer [pprint-str]])
            [hyperfiddle.electric3 :as e]
            [hyperfiddle.electric-dom3 :as dom]
            [hyperfiddle.electric-forms5 :as form]))

(defn px [n]
  (str n "px"))

(def row-height 24)

(e/defn Table [items Row]
  (dom/div
    (dom/style (dom/text form/css))
    (dom/props {:style {:height (px (* row-height (count items))
                        :--column-count 1}})
    (form/VirtualScroll :table :tr row-height 1 items Row)))

(e/defn ClientRow [!selection _index {:keys [id label]}]
  (e/client
    (dom/On "click" #(do
                       (println "ID:" id)
                       (swap! !selection conj id) nil) nil)
    (dom/td (dom/text label))))

(e/defn Main [ring-request]
  (e/client
    (binding [dom/node js/document.body
              e/http-request (e/server ring-request)]
      ; mandatory wrapper div 
      (dom/div (dom/props {:style {:display "contents"}})
               (let [options [{:id 1 :label "One"} {:id 2 :label "Two"} {:id 3 :label "Three"}]
                     !selection (atom #{}) selection (e/watch !selection)]
                 (Table options (e/Partial ClientRow !selection))
                 (dom/button (dom/text "Reset")
                             (dom/On "click" #(do (reset! !selection #{}) nil) nil))
                 (dom/div (dom/text "Selection:" (pr-str selection))))))))

Dustin Getz (Hyperfiddle) 2025-04-13T10:45:03.975259Z

yes, token is unnecessary for safe synchronous updates as there is no pending/retry state. Here is a client-only counter:

(dom/button (dom/On "click" (partial (fn [!n e] (swap! !n inc)) (atom 0)) 0))

🙏 1
Dustin Getz (Hyperfiddle) 2025-04-13T10:46:18.105069Z

in the virtual scroll case, as long as your atom is outside the scroll, which it is, this is fine

Dustin Getz (Hyperfiddle) 2025-04-13T12:37:00.779919Z

indentation - if you are using cursive, alt-enter to configure indentation for container macros

euccastro 2025-04-13T17:37:10.017979Z

Is it idiomatic for an electric function to take a map as an argument and destructure its fields? Or does that harm the granularity of reactivity in any way?

euccastro 2025-04-13T18:39:01.219929Z

I remember something about e/amb being preferred when passing multiple form values over passing them in a map for this reason, but I can't find the place in the tutorials where this is said (maybe this was only explained in Dustin's latest talk?)

euccastro 2025-04-13T18:40:23.966359Z

My guess would be that on any map update Electric will have to compare the new values of all destructured vars to the old ones (which would not be necessary if they had been passed as separate arguments), but after that it will work skip if it finds they have not changed?

euccastro 2025-04-13T18:41:01.690619Z

So, not terrible but better not to do it

noonian 2025-04-13T19:21:25.164719Z

I asked about this early in v3, but I think it was before all the amb docs were out. https://clojurians.slack.com/archives/C7Q9GSHFV/p1724137072396609?thread_ts=1724007358.949779&cid=C7Q9GSHFV I think it might be fine if the contents are all on client or server. I am currently passing server-side deps in a map to my client entrypoint and seems to work fine if I only access them from the server. If you want to use something on the client I think you'd need to destructure/get the value on the server and only reference that in a client block

👍 1
Dustin Getz (Hyperfiddle) 2025-04-13T19:57:55.573029Z

it depends, but definitely pass perf-sensitive objects as an explicit parameter. perf sensitive can mean - values that update frequently, values that are sensitive to accidental transfer, any kind of collection. Note that you cannot store electric tables (`e/amb`) inside clojure data structures, it implies a product. so basically - be careful.

👍 2
euccastro 2025-04-13T21:48:48.694599Z

Thanks to both! In my case I didn't have a particularly good reason to want map params, so I'll just avoid it

oλv 2025-04-14T15:08:32.360949Z

Could you add a tfoot element to dom3? I tried to add it myself but com.hyperfiddle/electric-secret {:local/root "../electric-secret"} stopped me.

👀 1
Dustin Getz (Hyperfiddle) 2025-04-14T15:15:15.328239Z

yes and you can add it in a userland ns for now as well

oλv 2025-04-14T15:16:01.028839Z

Will do, sorry for posting in a thread. I didn't notice 🤦‍♂️