reagent

Pepijn de Vos 2025-08-13T12:01:28.322919Z

Hmmm I seem to recall some docs on type 2 components but I can't find them

Pepijn de Vos 2025-08-13T12:04:40.882029Z

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.

Pepijn de Vos 2025-08-13T12:05:50.071759Z

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.

p-himik 2025-08-13T12:55:22.595279Z

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."

Pepijn de Vos 2025-08-13T14:47:48.042259Z

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.

p-himik 2025-08-13T14:51:08.631959Z

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.

Pepijn de Vos 2025-08-13T14:59:02.077339Z

How is re-frame different here?

p-himik 2025-08-13T15:00:42.654629Z

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.