reagent

souenzzo 2025-02-24T13:52:24.499229Z

Hello folks I'd like to share solution of an issue, that may help others. Setup: I'm using reagent@1.1.0, react@17.0.2 and antd@4.23.6 I was using the input like this, that I believe that is the "reagent default" option:

(defn ui-input-v1
  [{:keys [*value]}]
  [:> antd/Input {:value    @*value
                  :onChange (fn [e]
                              (reset! *value (.-value (.-target e))))}])
;; buggy version. the cursor keeps jumping to the end of input
#_[ui-input-v1 {:*value (r/atom "abc")}]
but this was causing the cursor to jump to the end while editing. I've been living with this for a few months. Today I discovered that if I use the new :f>, it will fix my issue:
(defn ui-input-v2
  [{:keys [*value]}]
  (let [[value on-change] (react/useState (str @*value))]
    (react/useEffect (fn []
                       (reset! *value value)))
    (react/createElement antd/Input #js{:value    value
                                        :onChange (fn [e]
                                                    (on-change (.-value (.-target e))))})))
;; NOT fully functional version (read the thread)
#_[:f> ui-input-v2 {:*value (r/atom "abc")}]

p-himik 2025-02-24T13:54:19.418429Z

In the second version, if something else changes the input ratom externally, will the input see the change?

souenzzo 2025-02-24T13:58:27.692109Z

good catch. I think that I need another useEffect with add-watch and something to "cleanup"

p-himik 2025-02-24T14:04:34.906449Z

Well, the ratom is deref'ed in the render function. But I have no clue how it works in that specific case with two hooks and a function component.

souenzzo 2025-02-24T14:08:14.462769Z

(react/useEffect (fn []
                   (let [ident (keyword (str (random-uuid)))]
                     (add-watch *value ident
                       (fn [_ _ prev next-value]
                         (prn [:prev prev next-value])
                         (on-change next-value)))
                     (fn []
                       (some-> *value (remove-watch ident)))))
  #js[])
This hook tecnically works, goes into loop with the prev state

p-himik 2025-02-24T14:09:09.135159Z

Oof.

souenzzo 2025-02-24T14:17:25.900549Z

OK. I will not use the ratom. :initial-state and :on-change will do for now

souenzzo 2025-02-24T16:00:02.662149Z

@p-himik do you understand why reagent has this issue with antd input's? (or antd has this issue with reagent components?!) Does this problem have a name?

p-himik 2025-02-24T16:07:46.997339Z

It's a common thing that for :input and :textarea Reagent fixes on its own end. There are some examples of doing it for thirdparty libraries used from Reagent. I usually use the double ratom approach - what re-com uses.

souenzzo 2025-02-24T16:11:55.791509Z

https://github.com/day8/re-com/blob/master/src/re_com/input_text.cljs#L66-L67 I will try to replicate

2025-02-24T18:39:59.409209Z

@souenzzo It happens because Reagent is batching the changes on the ratoms. There is a way to workaround the problem: https://github.com/reagent-project/reagent/blob/master/doc/ControlledInputs.md