This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-03-07
Channels
- # announcements (1)
- # architecture (9)
- # babashka (3)
- # calva (10)
- # clj-http (13)
- # clj-kondo (11)
- # clojure (23)
- # clojure-europe (11)
- # clojure-nl (1)
- # clojure-norway (112)
- # clojure-uk (4)
- # clojuredesign-podcast (8)
- # clojurescript (10)
- # core-async (5)
- # cursive (7)
- # data-science (15)
- # datascript (2)
- # datomic (29)
- # emacs (5)
- # events (1)
- # hugsql (1)
- # hyperfiddle (9)
- # midje (1)
- # missionary (3)
- # music (1)
- # off-topic (34)
- # polylith (1)
- # re-frame (16)
- # shadow-cljs (117)
- # squint (19)
- # yamlscript (1)
Is it possible to use plain dynamic binding with plain Clojure values on the server? I'm keeping some state on the server for each connection. I might like to do something like:
#?(:clj (def ^:dynamic !client-state))
(e/def client-state)
(e/defn Main [ring-request]
(e/server
(binding [!client-state (atom {})]
(binding [client-state (e/watch !client-state)]
...)))))
This fails because !client-state
isn't an e/def. Of course I can make it an e/def:
(e/def !client-state)
(e/def client-state)
(e/defn Main [ring-request]
(e/server
(binding [!client-state (atom {})]
(binding [client-state (e/watch !client-state)]
(UI.)))))
I'm not sure if this is a hack, or a natural way of lifting a Clojure value into the Hyperfiddle DSL using a constant reactive value 🙂That looks good to me. You can put multiple bindings in binding
, so no need to nest them.
I don't know about the hyperfiddle DSL, but my understanding was that Clojure's binding was executed in parallel.
If anyone is interested, we’re employing a React-inspired macro to declare state. E.g.,
(let [[current-count set-count!] (use-state 0)]
(dom/div (dom/text (str current-count)))
(dom/button
(dom/text "Increment")
(dom/on! "click" #(set-count! inc)))
(dom/button
(dom/text "Reset")
(dom/on! "click" #(set-count! 0))))
What do you think is the benefit over just using the native clojure atom ops?
Three minor things that just about add up to being worth it (in our opinion): • Slightly more convenient to write, as the atom itself is inconsequential in 99% of cases: you want its value and a way to manipulate it. • In the same vein, you have a setter that by virtue of the interface gets named closely to what it does. So, slightly cleaner semantics and a more direct way to get to them. • The shape and function is familiar to React users, or users of UIx and other libs that follow the React form and function.
Similarly, we have a $
macro as well (inspired by UIx).
So the above might look something like this in our codebase:
(let [[current-count set-count!] (use-state 0)]
($ :div ($ :text (str current-count))
($ Something {:hello :world})
($ :button {:class […]}
($ :text "Increment")
(dom/on! "click" #(set-count! inc)))
($ :button {:class […]}
($ :text "Reset")
(dom/on! "click" #(set-count! 0)))))
I.e., $
used for both instantiating reactive functions and dom elements, and to elide dom/props
when the payload is a straight map (which it is most of the time).