(def s (r/atom 0))
(defn foo []
[:input {:type "text"
:value @s
:on-click #(reset! s (.-target.value %)}]) ; unstable closure reference
(defn change [e] (reset! s (.-target.value e)) ; you're suggesting we name it
(defn foo2 []
[:input {:type "text"
:value @s
:on-click change}]) ; which works here - this is now a stable function reference. Good!
; But what if the named function is not static, but a closure
(defn foo3 [something]
(let [change' (fn [e] ; closure instance is rebuilt each render
(if something
(reset! s (.-target.value e))))]
[:input {:type "text"
:value @s
:on-click change'}])) ; unstable closure reference
The answer generally is to do what you say and hoist up any closures to static scope, like foo2 here.
Even foo3
can be written into a hoisted static function with additional parameters, and use reagent.core/partial
instead of clojure.core/partial
to preserve stabiltiy. But it is not always reasonable and it can cause great contortions in your code when you're basically no longer allowed to write (fn [])
ever again.
@didibus If Reagent reflected the function (closure!!!) name in order to stabilize it, it would introduce incorrect/buggy behavior, because the closure may indeed have re-evaluated in a way that in fact shouldn't compare equal. Consider
foo3
wheresomething
parameter (closed over from lexical scope) evaluates differently