Hello, I have experimented with implementing a counter in Electric 3 as:
(e/defn Counter [p]
(case (e/Task (m/sleep 100))
(e/amb p (Counter (inc p)))))
(dom/div (dom/text (Counter 0)))
It works, but is eating all the memory after some time. Is there a solution for this, concerning freeing somehow the resources? What am I doing wrong?
Thanks for any insights!ha yes that is building a collection like [1 2 3 4 5 ...], and then racing the elements into a single dom/text. use (dom/text (pr-str (e/as-vec (Counter 0)))) to see the whole collection
have you seen https://electric.hyperfiddle.net/tutorial/counter
Thanks, Dustin! Yes, it is a great implementation and tutorial. Actually, I would like to have something similar to Missionary flow clock implementation, but doing with Electric (e/amb), growing and freeing in time.
(m/ap (loop [] (m/amb nil (do (m/? (m/sleep 100)) (recur)))))
Does it make sense?you can use e/input to use that from Electric
I can probably come up with a native electric version if i have free time later
Yes, I have the implementation with (e/input), but thinking about native Electric exactly!
e/with-cycle
(e/with-cycle [n 0] (+ n (e/Task (m/sleep 100 1))))
not sure if the sleep needs a causal dependency on n
Thanks! As I understand, the implementation with (e/with-cycle) forces the use of an atom, compared to aka "forking flow" with (e/Task) and self referencing? I would also like to explore these direction of the implementation, if possible and reasonable.
We would encourage you not to think of with-cycle as stateful, we consider this a pure functional pattern. The fact that it happens to use an atom internally is because the stateful implementation is equivalent to the fastest possible implementation if we were to reify this as a special form inside the electric compiler
There is state everywhere in electric, every let binding and every function argument is memoized
Another example is how we use atoms to loop up a value in lexical scope, in apps like https://electric.hyperfiddle.net/tutorial/system_properties
in haskell dataflow this can be accomplished with recursive let bindings, and when electric eventually gets that feature, we too can eliminate the explicit atom. But the state will still be present, it is just hidden inside the let 's memo buffer
https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/recursive_do.html#recursive-binding-groups
played a bit more, basically one day perhaps the latter can be syntactically valid, i think it is well defined
(dom/text
(e/with-cycle [n 0]
(+ n (e/Task (m/sleep 100 1)))))
(let [n (+ (e/Some (e/amb n 0)) (e/Task (m/sleep 100 1)))] ; recursive binding, i.e. a dataflow loop
(dom/text n))(e/Some x) is a made up function which takes the first non-e/amb value from x
What am I doing wrong?
(e/defn Button [label f]
(dom/button (dom/props {:class "bg-red-600 text-white rounded px-4 py-1 m-2"
:href "#"
:type "button"})
(dom/text label)
(dom/On "click" f nil)))
(e/defn SimpleInput [m-atom k]
(form/Input (k @m-atom)
:parse (fn [x] (swap! m-atom assoc k x))
:class "rounded py-1 px-2 mx-2 shadow border"))
(e/defn Systems []
(e/server
(let [current-user* (-> (f/coll db "users") (f/doc "test") f/->atom)
current-user (e/watch current-user*)]
(e/client
(dom/div
(dom/props {:class "m-4 space-y-4"})
(Avatar current-user)
(let [result (atom {:firstname (get current-user "firstname")
:lastname (get current-user "lastname")})]
(dom/form
(style "p-4 border rounded")
(dom/label (dom/text "First Name:"))
(SimpleInput result :firstname)
(dom/text "Last Name:")
(SimpleInput result :lastname)
(Button "Save Changes"
(e/fn []
(e/client (js/alert (str "Saving " @result)))
(e/server (-> db (f/coll "users")
(f/doc "test")
(f/assoc! "firstname" (:firstname @result)))))))))))))
On the last line - if I pass a normal clojure function there, it works and runs in the browser, trying to pass an e/fn which does something on the server, clicking the button does nothing now and I can’t figure out what I should be doing differently. can dom/On take an e/fn?u
(One thing that does work really nicely though is the reactivity of Firestore, stuff on the page just magically updating when it changes in the db)
I realise I should probably be using forms3, but couldn’t figure out how you were meant to style your form (given the visual component is implemented in the same function as the value storage - I get the input rendered as a side effect when trying to put all the components of my form in a map!) and put your own Save/reset buttons etchttps://electric.hyperfiddle.net/tutorial/token_explainer to understand how one should use dom/On. The next tutorials cover the current status of forms
> can dom/On take an e/fn No, there is a brief explainer why under "simple free text input" in https://electric.hyperfiddle.net/tutorial/system_properties
Electric v2 did this (allowing "electric callbacks" to process events and potentially switch to the server) but it had many many problems, which led us to the e/Token pattern that @xifi linked above
you can provide a SimpleButton component like this if you really want to think in electric callbacks - but it won't scale to the sophisticated "enterprise" patterns (table pickers and such like in https://electric.hyperfiddle.net/blog/y20250112_data_browser/(:branches)/(9))
here is a https://gist.github.com/dustingetz/b0e7f92ba753e61122a2d4a136bd93dc using MyButton
I realise I should probably be using forms3, but couldn’t figure out how you were meant to style your formyeah i do not think we have "unbundled" the form yet for full layout control (button placement etc) - you didn't do anything wrong.
fwiw hyperfiddle.forms-* is very bleeding edge and is intended to express Complicated Enterprise Forms such as this attached. The pattern may not be worth it for less complicated forms, and the pattern is definitely not "finished"
I mean the pattern I'm intuitively trying to recreate is the formik one more or less, where the form state is a simple map, the form renders based on that state map and the inputs reach in and update the values, the commit function takes the full map and returns a map with any errors etc, which then get simply rendered, and pending states can likewise be managed by just associng the pending state into the map at the start of the commit function
https://electric.hyperfiddle.net/tutorial/form_list is pretty close to that i think? form state as map L15, toggle failure checkbox off to see that committing to one form updates both
here's an unpublished demo with validation at field and form level, w/ working retry state - (edit: fixed link) https://electric.hyperfiddle.net/staffly.staffly!Staffly/:restrict-staff-from-venue/17592186045437/'restrict'
Not really, that stores the latest value in a map site, but it doesn't style the full state of the form. I.e. does a specific field have validation errors, is it dirty etc, which in formik you'd then use when rendering your form if you wanted to show eg that you've edited a field since last save or have a custom field error or list of field error renderings. The forms3 way all that seems tied into the component implementation so I don't see how you'd decouple it to do anything vaguely custom, and it's very opinionated at it stands. Guess it depends whether you're going for a headless philosophy where the workings are decoupled from the rendering or bootstrap batteries included, everything looks and works the same but you're on your own if you want to do anything different
example of custom : https://electric.hyperfiddle.net/tutorial/todomvc
yes, it uses the forms patterns
(not claiming it's perfect or finished, as i said this is all very bleeding edge, you are basically expected to either read the source or hire us)
oops, above form demo url was broken, fixed link - https://electric.hyperfiddle.net/staffly.staffly!Staffly/:restrict-staff-from-venue/17592186045437/'restrict'