Callbacks as Clojure Records: an approach to generic Reagent components

If i had this situation (rare because re-frame doesn’t encourage much prop drilling) and it was performance sensitive, I’d reify the callbacks so they tested = to before. This technique requires that you use a form-2 view.

Code sketch:

Have a utility function like this around the place:

(defn cb-factory-factory
  [real-callback]
  (let [*args1     (atom nil)
        cb-wrapper (fn [& args2]
                     (apply real-callback (concat @*args1 args2)))]
    (fn [& args1]                  ;; id comes in as args 
      (when (not= args1 @*args1) 
        (reset! *args1 args1))
      cb-wrapper)))               ;; <-- always return the same fucntion

Then use it:

(defn some-view 
  [_]
  (let [on-click          (fn [id] (re-frame/dispatch [:something id]))
        on-click-factory  (cb-factory-factory on-click)
        on-change         (fn [id event] (re-frame/dispatch [:it-changed id (-> event .-target .-value)]))
        on-change-factory (cb-factory-factory on-change)]

    (fn [some-id]
      [:<>
       [:div  {:on-click (on-click-factory some-id)}]        
       [:input {:type      "text" 
                :value     "Hello"
                :on-change (on-change-factory some-id)}] ])))

Sounds like I should document this??

BTW, do not take this as the only way to do it. There’s a bunch of simple variations on this kind of approach subject to your needs, particularly when, in re-frame, most of your handlers are dispatching allowing you to be simpler and more specific.

1 Like