This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-05-21
Channels
- # calva (11)
- # cider (4)
- # clojure (15)
- # clojure-europe (20)
- # clojurescript (14)
- # clr (45)
- # conjure (2)
- # cursive (1)
- # fulcro (10)
- # helix (4)
- # honeysql (7)
- # hoplon (21)
- # humbleui (2)
- # hyperfiddle (23)
- # introduce-yourself (1)
- # malli (11)
- # matrix (3)
- # off-topic (6)
- # pathom (2)
- # practicalli (1)
- # re-frame (9)
- # releases (1)
- # specter (2)
- # sql (10)
- # xtdb (2)
Hello! I have a (hopefully) small question. When I do this:
(def ctext (cell "Hello!"))
(defn hello []
(h/div
ctext
(h/input {:input #(reset! ctext (-> % .-target .-value))})))
On each char I type in input the input lose focus, why is that?
(it seems to rerender for some reason)This solves the issue:
(h/div
(h/text ctext)
(h/input {:input #(reset! ctext (-> % .-target .-value))}))
Look like something related to the rerender of div with direct text that causes the rerender of inputWhat is the reason h/text
has to be a macro?
it doesn't have to be, but h/text supports interpolation
looked into this a little more, i think the relevant code is here:
https://github.com/hoplon/hoplon/blob/master/src/hoplon/core.cljs#L299-L300
in your first example, ctext
is a cell and goes down the first, (`cell? child)` path. in that case, when the value of child
changes, the kids
cell<vector> associates element at i
(size of kids vector at append time) with the ctext cell's new value
in the second example, (h/text ctext)
evaluates to a DOM textNode and not a cell: https://github.com/hoplon/hoplon/blob/master/src/hoplon/core.clj#L229-L230
in the second example, the DOM textNode is "static" in the sense that its contents can change internally over time, but as far as the kids cell<vector> it's contained in, it never changes. its value is mutated independently by the cell created in h/text
so, back in -append-child!
, the non-cell gets appended via (swap! kids assoc i child)
zooming out, this touches on some of the design implications of a relationship between data model and DOM in a "retained mode" graphics model. and also the stange algebra of cell/non-cell composition that emerges
finally, i think the first example loses focus because changing ctext
modifies the div's kids
, and the children get removed and re-attached whenever the ctext
cell changes
anyway, hope that all makes some kind of sense, happy to elaborate in any direction in case not
Another question: what is the difference?:
(cell= (str "Hello, " (cell "John")))
(let [a (cell "John")]
(cell= (str "Hello, " a)))
((formula str) "Hello, " (cell "John"))
the 1st example returns "Hello, [object Object]"
the 2nd & 3rd return "Hello, John"
in the first example a cell is created inside a formula and the enclosing cell=
is not generating code to derefence the cell before passing to str
i think it's because cell=
wraps free variable names with maybe-dereference magic, but arbitrary expressions (`(cell "Jon")` are not
note also that example 2 is representative by far the most common usage, naming a cell outside of a cell= so you can manipulate it
if I have the following use case:
(def m {:a (cell 1)
:b (cell 2)})
(cell= (+ (m :a) (m :b)))
where I want to bundle some cells in a structure, and compute over them.
please note I'm already aware of the option of let
:
(let [a (m :a)
b (m :b)]
(cell= (+ a b)))
The catch here is that I also get the computation as a variable and I can't break the computation and extract the cells out, think of something like this:
(def m {:a (cell 1)
:b (cell 2)})
(def c (+ (m :a) (m :b)))
(cell= c)
Is there any solution that you can recommend?You could have a bigger cell if that is not a problem in you use case:
(def m (cell {:a 1
:b 2})
(cell= (+ (m :a) (m :b)))
But I lose granularity, correct?
You mean you will have fewer cells that will trigger bigger updates on formula cells? This is correct but in my experience not a practical problem. I'm not sure about the problem that you are trying to solve to offer other options of how to do it.
The problem I'm trying to solve is quite complex and boil down to having cells in a structure and being able to create reactive computations based on them without explicitly declare them (the cells).
I think formula
could work in that situation, the 3rd option in your initial message in this thread.
but how would you break c:
(def m {:a (cell 1)
:b (cell 2)})
(def c (+ (m :a) (m :b)))
(cell= c)
into its operation and operands? the are "applied away".
And if its a more complex expression it will be even harder, this is basically what cell=
does.(def m {:a (cell 1)
:b (cell 2)})
(def c (formula +))
(def result (c (:a m) (:b m)))
(cell= (js/console.log {:result result}))
note also that when dealing with structured updates, lenses can be useful