Search code examples
clojureclojurescriptreagentre-frame

Why is this def used in the re-frame todomvc app?


See the re-frame todomvc views namespace :

This file contains the following def

(def todo-edit (with-meta todo-input
                      {:component-did-mount #(.focus (r/dom-node %))}))

which is called from the todo-item function.

I understand that 'component-did-mount' is a phase in a react.js component life cycle but I don't understand the purpose nor meaning of this def. Why is it necessary ?

Please explain.


Solution

  • The purpose is entirely to provide the component-did-mount lifecycle function.

    The def is creating todo-edit which is just a todo-input which will run some code when the dom node is mounted. Note that Reagent components are functions which run before the dom node exists, so you can't normally do things like calling focus. If they return a function, the function runs ever render, which you would not want to call focus on or the form would be unusable.

    Reagent looks for lifecycle methods on functions attached as meta data. When this input is mounted, it will call the focus method on the dom node.

    Setting the autofocus attribute is a lightweight alternative.

    Working with meta-data to do this is clunky and should be avoided.

    A Form-3 component definition looks like this:

    (defn my-component
      [x y z]  
      (let [some (local but shared state)      ;; <-- closed over by lifecycle fns
            can  (go here)]   
         (reagent/create-class                 ;; <-- expects a map of functions 
           {:component-did-mount               ;; the name of a lifecycle function
            #(println "component-did-mount")   ;; your implementation
    
            :component-will-mount              ;; the name of a lifecycle function
            #(println "component-will-mount")  ;; your implementation
    
            ;; other lifecycle funcs can go in here
    
            :display-name  "my-component"  ;; for more helpful warnings & errors
    
            :reagent-render        ;; Note:  is not :render
             (fn [x y z]           ;; remember to repeat parameters
                [:div (str x " " y " " z)])})))
    

    The official reagent tutorial doesn't show how to do Form-3 components in the way shown above, and instead suggests that you use with-meta, which is clumsy and inferior.