reagent

A minimalistic ClojureScript interface to React.js http://reagent-project.github.io/
Joe 2020-09-26T13:09:36.005200Z

Hello I'm having trouble getting a form 3 CodeMirror component to re-render when I want it to. I have the component model-input, which is instantiated with a 'selected-measure' atom received from a subscription. I extract the code for the selected measure, and wrap in local-state atom code. I then instantiate the codemirror component with the code, and the component unwraps it and displays it. The model-input also has a dropdown which selects the measure and dispatches something that should trigger the model-input to re-render, and I would assume the codemirror also. I can see the local state in model-input is changing when the dropdown is changed, but the codemirror is not, and I don't get why. I'm guessing I'm either missing something in the form 3 component, or not understanding the re-render logic. Any thoughts? https://github.com/RedPenguin101/modeldsl/blob/codemirror-redo/src/model_dsl/frontend/main.cljs Thanks in advance

Joe 2020-09-26T13:10:19.005400Z

Here's an abbreviated version of the code if that's simpler

(defn app []
   ,,,
   [:div#input.columns
    [:div#model.column
     [:h4.title.is-4 "Model"]
     [model-input (rf/subscribe [:selected-measure])]]]
   ,,,)

(defn model-input [selected-measure-atom]
  (fn [selected-measure-atom]
    (let [{:keys [name code]} @selected-measure-atom
          code (r/atom code)]
      [:div 
       ,,,
       [measure-dropdown]
       [codemirror code {:name name}]
       ,,,])))

(defn codemirror [value-atom options update]
  (let [options (merge {:mode "clojure"} options)]
    (r/create-class
     {:reagent-render (fn [] [:div])
      :component-did-mount
      (fn [component]
        (let [editor (create-codemirror
                      (rd/dom-node component)
                      (assoc options
                             :value @value-atom))]
          (.on editor "change"
               #(reset! value-atom (.getValue editor)))))})))

(defn create-codemirror [elem options]
  (js/CodeMirror.
   elem
   (clj->js options)))

Joe 2020-09-26T13:19:42.005600Z

I tried adding a component-did-update key to codemirror but it started doing some weird things, so I thought that was probably the wrong approach.

p-himik 2020-09-26T13:24:22.005800Z

value-atom is never updated. You should get it from the new properties in the :component-did-update function.

Joe 2020-09-26T14:10:30.006Z

Would value-atom (which is actually code) not be updated when the :selected-measure subscription fires in app?

p-himik 2020-09-26T14:18:54.006200Z

codemirror is a form-3 component. Its [value-atom options update] arguments are used only when it's mounted. All the subsequent updates are passed to :component-did-update. Similar to form-2 components - the outer function receives its arguments when the component is mounted. All the subsequent updates change only the arguments of the inner function. Unless there's a :key metadata, but that's a whole other story.

Joe 2020-09-26T15:55:44.006500Z

Thanks! Not sure I've got my head around it TBH, but after adding the :component-did-update it is working now.

👍 1
p-himik 2020-09-26T15:56:53.006800Z

Reagent and re-frame documentation is a great read that answers many similar questions.