Hmmm I seem to recall some docs on type 2 components but I can't find them
I'm basically trying to build the following combobox component that lets you select from a list but then edit the selection:
(defn dbfield [typ props st valfn changefn]
(let [int (r/atom @st)
ext (r/atom @st)
dbfn (debounce changefn)]
(fn [typ props st valfn changefn]
(when (not= @ext @st)
(reset! int @st)
(reset! ext @st))
[typ (assoc props
:value (valfn @int)
:on-change (fn [e]
(let [val (.. e -target -value)]
(dbfn st val)
(changefn int val))))])))
(defn combobox-cursors [vector-cursor]
(let [index-cursor (r/atom 0)
element-cursor (r/cursor vector-cursor [@index-cursor])]
[element-cursor index-cursor vector-cursor]))
(defn combobox-field [[element-cursor index-cursor vector-cursor] valfn changefn]
[:div.combobox-group
[dbfield :input {:class "combobox-input"} element-cursor valfn changefn]
[:select {:class "combobox-select"
:value @index-cursor
:on-change #(reset! index-cursor (js/parseInt (.. % -target -value)))}
(doall (map-indexed
(fn [i item]
[:option {:key i :value i} (valfn item)])
@vector-cursor))]])
The problem seems to be where to store those state atoms. vector-cursor is something that depends on other state so might get recreated. But what seems to happen is that it also recreates the index atom so you can't change the select box.I thought, I know I'll use a type 2 component and put all those state atoms outside so they don't get reset. But as I said the vector-cursor does depend on other things so if you put them outside they never update at all.
I would most definitely suggest trying your damnest to avoid changing the references themselves, such as vector-cursor. Let spaghetti stay a dish.
Because otherwise you'd have cause and effect strewn across your whole codebase with no clear sense as to what's going on exactly and with inscrutable bugs that are nearly impossible to debug. "If I do X, then do Y, then do Z, then go back and navigate to A - the B functionality doesn't work anymore until I refresh the page."
I mean, it's mostly stuff like this
(let [mod (r/cursor db [@selmodel])
so that the code below it can easily access and change the selected model. The alternative seems to be to strew get-in and update-in all over the place.Maybe I've simply forgotten how to write in plain Reagent... It's a bliss not having to deal with all of that in re-frame. The hardest part is to decide on how exactly you want to pass data around - IDs, paths, functions,... But regardless, if would simply work. I don't even write form-2 or form-3 components now, unless it's for interoping with some stateful JS library.
How is re-frame different here?
You don't use cursors or tracks or reactions, ever. Unless something gnarly is going on. You don't pass ratoms of any kind around.