考虑以下试剂成分。它使用ref函数,该函数根据span元素的实际大小更新局部状态原子。这样做是为了重新渲染显示其自身大小的组件
(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)]])))
如果get-real-size
的实现返回向量,则会不断打印日志消息,这意味着组件不必要地一直被重新呈现。如果它只返回一个数字或一个字符串,则日志只会出现两次 - 就像在这种情况下一样。
这是什么原因?是否可能使用新的向量更新clojure脚本原子(虽然包含相同的值)在内部意味着将另一个JavaScript对象放在那里,从而改变原子?放一个值会产生无法观察到的变化吗?只是猜测...... *
无论如何 - 对于真实的用例,在向量中保存跨度的大小肯定会更好..有没有办法实现这个目标?
当我尝试增强this问题中给出的答案时,我突然想到了这一点。
*因为在JS:({} === {}) // false
答案 0 :(得分:3)
我想我有一个答案,为什么矢量的行为与字符串/数字不同。试剂计数试剂原子为"改变" (当identical?
在旧值和新值之间返回false时,(并因此更新依赖于它的组件)。见副标题"已更改?"在this tutorial中:
对于ratoms,相同?使用(在ratom内的值)来确定新值是否相对于旧值发生了变化。
然而,事实证明identical?
对于向量和字符串/整数的行为有所不同。如果您启动clj或cljs repl,您将看到:
(identical? 1 1)
;; true
(identical? "a" "a")
;; true
(identical? [1] [1])
;; false
(identical? ["a"] ["a"])
;; false
如果您查看identical?
here做什么,您会看到它测试其参数是否是相同的对象。我认为潜在的内部数据表示是这样的,在clojure中," a"始终是与自身相同的对象,而包含相同值的两个向量不是彼此相同的对象。
确认:使用普通原子而不是试剂原子,我们可以看到在原子重置时保留了字符串标识,而矢量标识则没有。
(def a1 (atom "a"))
(let [aa @a1] (reset! a1 "a") (identical? aa @a1))
;; true
(def a2 (atom ["a"]))
(let [aa @a2] (reset! a2 ["a"]) (identical? aa @a2))
;; false
答案 1 :(得分:2)
您可以使用not=
支票解决问题:
(fn [el]
(when el
(let [s (get-real-size el)]
(when (not= s @size)
(reset! size s)))))
我不确定为什么矢量应该与其他值不同的原因是什么。
答案 2 :(得分:0)
根据它的编写方式重新渲染它。您要在重置原子时使用相同的功能来使其失效。我总是将它们分开。
(defn span-size [size]
[:span (prn-str @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-size]])))