clojurescript 原子的哪些变化会导致试剂成分重新渲染?

Ant*_*ald 2 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)]])))
Run Code Online (Sandbox Code Playgroud)

如果 的实现get-real-size返回一个向量,则日志消息会不断打印,这意味着组件一直在不必要地重新渲染。如果它只返回一个数字或一个字符串,则日志只会出现两次 - 正如本场景中所预期的那样。

这是什么原因?是否可能在内部使用新向量(尽管包含相同的值)更新 clojure 脚本原子意味着将另一个 JavaScript 对象放在那里,从而更改原子?而放置一个值不会产生可观察到的变化?只是猜测...*

无论如何 - 对于实际用例,将跨度的大小保存在向量中肯定会更好.. 有没有办法实现这一点?

我在尝试增强问题中给出的答案时遇到了这一点


* 因为在 JS 中: ({} === {}) // false

Pau*_*der 6

我想我有一个答案,为什么矢量的行为与字符串/数字不同。当identical?在旧值和新值之间返回 false时,试剂将试剂原子计数为“已更改”(从而更新依赖于它的组件)。看到小标题“改变了吗?” 在本教程中

对于ratom,相同吗?用于(在随机数内的值上)确定新值是否相对于旧值发生了变化。

然而,事实证明identical?对于向量和字符串/整数的行为不同。如果您启动 clj 或 cljs repl,您将看到:

(identical? 1 1)
;; true 
(identical? "a" "a")
;; true 
(identical? [1] [1])
;; false
(identical? ["a"] ["a"])
;; false
Run Code Online (Sandbox Code Playgroud)

如果你看看这里identical?什么,你会看到它测试它的参数是否是同一个对象。我认为底层的内部数据表示是这样的,在 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
Run Code Online (Sandbox Code Playgroud)