Consider the following reagent component. It uses a ref function, which updates a local state atom, based on the real size of a span element. This is done in order to re-render the component displaying its own size
(defn show-my-size-comp []
(let [size (r/atom nil)]
(fn []
(.log js/console "log!")
[:div
[:span {:ref (fn [el]
(when el (reset! size (get-real-size el))))}
"Hello, my size is:" ]
[:span (prn-str @size)]])))
If the implementation of get-real-size
returns a vector, the log message is printed constantly, meaning the component unnecessarily being re-rendered all the time. If it returns just a number or a string, the log appears only twice - as intended in this scenario.
What's the reason for this? Is it maybe that updating an clojure script atom with a new vector (containing the same values though) internally means putting another JavaScript object there, thus changing the atom? Whereas putting a value produces no observable change? Just speculation...*
Anyways - for the real use case, saving the size of the span in a vector would certainly better.. Are there ways to achieve this?
I cam across this, when trying to enhance the answer given in this question.
* since in JS: ({} === {}) // false
You can work around the problem with a not=
check:
(fn [el]
(when el
(let [s (get-real-size el)]
(when (not= s @size)
(reset! size s)))))
I'm not sure what the reason is for why vectors should differ from other values.