对clojurescript原子进行哪些更改会导致试剂成分重新渲染?

时间:2016-08-26 19:24:31

标签: clojure clojurescript reagent

考虑以下试剂成分。它使用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

3 个答案:

答案 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]])))