This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-11-12
Channels
- # babashka (4)
- # beginners (49)
- # biff (17)
- # calva (12)
- # cider (5)
- # clojure-czech (1)
- # clojure-europe (3)
- # clojure-norway (3)
- # core-logic (1)
- # cursive (4)
- # data-science (2)
- # datalevin (7)
- # emacs (1)
- # events (6)
- # fulcro (11)
- # helix (7)
- # hyperfiddle (30)
- # lsp (4)
- # podcasts-discuss (1)
- # practicalli (4)
- # releases (1)
- # remote-jobs (7)
- # ring (6)
- # spacemacs (4)
- # tools-deps (5)
Hello fellow electricians! 👋 ⚡
I've run into an issue with hyperfiddle.electric-ui4/button
firing its handler function more than once when the function updates the state that function handler depends on.
In the simplest reproducible example, a button handler updates a server-side atom (the issue does not happen when atom is client-side only), but since handler depends on the atom's value, the handler gets executed twice (or more in more complex scenarios): once with initial state and then with its updated state.
Please take a look at the gif below and here's https://github.com/hyperfiddle/electric-starter-app/compare/main...roterski:electric-starter-app:2023-11-12-button-firing-twice-bug-showcase.
Is this a known issue? I could probably circumvent it somehow, but I'd argue that's an unexpected (and undesired?) behavior of a ui/button
that can lead to pretty painful bugs (e.g. double-firing backend transactions).
known issue, search for many discussions explaining what’s happening, use e/snapshot to work around. next version of electric-ui is callback free
thanks! I've managed to work around it with e/snapshot
like this:
(e/defn Page
[]
(e/server
(let [!state (atom 0)
state (e/watch !state)]
(e/client
(ui/button
(e/fn []
(let [state (e/snapshot state)]
(println "client CLICK " state)
(e/server
(println "server CLICK " state)
(swap! !state inc))))
(dom/text "button"))))))
note that the transaction here (swap!) does not depend on state, the thing causing the cycles are the printlns. if you remove the printlns you don’t need snapshot
you need to understand this to use ui4 unfortunately, ui4 is robust to latency and concurrency but only if you understand the rules
ui5 will be easier
I am making a svg canvas with nodes and edges connecting these nodes. Each node has a location on the canvas, directed edges are defined in terms of "to" and "from" ids of nodes. I am not sure what is the electric way of updating the position of edges in the canvas is.
When some node is moved in the canvas I update its position in the server and watch for the changes in the client. Should I do the same for edges or should I use m/observe
and listen only on the client side?
I think I can model the data in another format so instead of directed edges are defined in terms of "to" and "from" ids of nodes I will store the incoming and outgoing edges in nodes itself.
So yeah I am confused, on one hand I have all the freedom to model as I want because of electric but on the other hand I am thinking is this the electric way, should I change my thinking to better use the power of electric.
As of now this is all in prototype stage, I am building for future where I would have millions of these nodes and even if I would be seeing some very small subset of them they could change because another agent changed some other part of the graph and maybe that changes some part of my view
please post code (i mostly read this on mobile so please post in a mobile friendly way, use the file attachment feature for longer snippets)
Here I attached the whole code part of it is some logic to convert b/w different coordinate systems and calculating position on canvas when circle is moved. view
, circle
and line
function are the ones that would be directly related to the problem
I was not using it previously, but since you mentioned I re-read my code, docs and some chat. I was using e/for-by
under client but the values are on server so I fixed it and now using value from the server like so (14 loc)
Now the UI is lagging more I think due to the nested for-by.
early stage but I'm learning datavis and creating a datavis gallery in electric https://github.com/groundedsage/electric-datavis-gallery
I'll be using this as a way of exploring the idiomatic electric way to do data visualisations.
I wasn't able to figure out how to determine when an element is mounted to the dom and opted for a timeout to start the animation. How do I change this code so that it runs when mounted. https://github.com/groundedsage/electric-datavis-gallery/blob/main/src/app/animation/connected_scatterplot.cljc#L144-L151
you can capture a ref to dom/node like this:
(let [el (dom/svg ... dom/node)] ...)
the key is that the dom syntax macros return the final child
you can also move the .beginElement effects into the body of svg/animate
where dom/node
is available, giving you a dependency on it
in your case i think that is sufficient?
for harder use cases if establishing a causal dep in the DAG is too difficult you can use the MutationObserver API, at least until we have time to take a look at making this better
Cool. The returning dom/node into a let binding is a good trick. It’s needed to actually get the length of a line because calling it inside that is not available. I still haven’t quite landed on animating after everything is loaded. By the time the visualisation renders its like 1/3 of the way through the animation. I’ll keep playing with it 🙂
Looking more at mutation observer I might need that.
Solved this using Web Animations API and capturing dom/nodes
how do you guys deal with uuid format differences between clj and cljs?
;; throws java.lang.IllegalArgumentException: Invalid UUID string: 100
(e/client
(ui/button (e/fn []
(let [id (uuid "100")]
(e/server id)))
(text "press me")))
hopefully none or minor changes to current APIs, maybe some additions
why do you ask