clojurescript 原子的哪些更改会导致试剂组件重新呈现?
Which changes to clojurescript atoms cause reagent components to re-render?
考虑以下试剂成分。它使用一个 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
returns 向量,日志消息会不断打印,这意味着组件一直不必要地重新渲染。如果它 returns 只是一个数字或字符串,则日志只出现两次 - 如本场景中所预期的那样。
这是什么原因?是否可能在内部用新向量(尽管包含相同的值)更新 clojure 脚本原子意味着将另一个 JavaScript 对象放在那里,从而改变原子?而放置一个值不会产生可观察到的变化?只是猜测...*
无论如何 - 对于实际用例,将跨度的大小保存在向量中肯定会更好。有什么方法可以实现吗?
我在尝试增强 问题中给出的答案时偶然发现了这一点。
* 因为在 JS 中:({} === {}) // false
您可以通过 not=
检查解决此问题:
(fn [el]
(when el
(let [s (get-real-size el)]
(when (not= s @size)
(reset! size s)))))
我不确定向量与其他值不同的原因是什么。
我想我已经找到了为什么 vector 的行为与 string/number 不同的答案。当旧值和新值之间的 identical?
returns 为假时,试剂将试剂原子计数为 "changed"(并因此更新依赖它的组件)。请参阅 this tutorial 中的副标题 "changed?":
For ratoms, identical? is used (on the value inside the ratom) to determine if a new value has changed with regard to an old value.
然而,事实证明 identical?
对向量和 strings/ints 的行为不同。如果你启动 clj 或 cljs repl,你会看到:
(identical? 1 1)
;; true
(identical? "a" "a")
;; true
(identical? [1] [1])
;; false
(identical? ["a"] ["a"])
;; false
如果您查看 identical?
的作用 here,您会发现它测试其参数是否 相同 object .我认为底层内部数据表示是这样的,在 clojure 中,"a" 始终与自身相同 object,而包含相同值的两个向量彼此不同 object .
确认:对于普通原子而不是试剂原子,我们可以看到字符串标识在原子重置时得以保留,而矢量标识则不然。
(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
它的重新渲染就像它应该基于它的编写方式一样。您正在使用与重置原子相同的函数取消引用原子。我总是把它们分开。
(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]])))
考虑以下试剂成分。它使用一个 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
returns 向量,日志消息会不断打印,这意味着组件一直不必要地重新渲染。如果它 returns 只是一个数字或字符串,则日志只出现两次 - 如本场景中所预期的那样。
这是什么原因?是否可能在内部用新向量(尽管包含相同的值)更新 clojure 脚本原子意味着将另一个 JavaScript 对象放在那里,从而改变原子?而放置一个值不会产生可观察到的变化?只是猜测...*
无论如何 - 对于实际用例,将跨度的大小保存在向量中肯定会更好。有什么方法可以实现吗?
我在尝试增强
* 因为在 JS 中:({} === {}) // false
您可以通过 not=
检查解决此问题:
(fn [el]
(when el
(let [s (get-real-size el)]
(when (not= s @size)
(reset! size s)))))
我不确定向量与其他值不同的原因是什么。
我想我已经找到了为什么 vector 的行为与 string/number 不同的答案。当旧值和新值之间的 identical?
returns 为假时,试剂将试剂原子计数为 "changed"(并因此更新依赖它的组件)。请参阅 this tutorial 中的副标题 "changed?":
For ratoms, identical? is used (on the value inside the ratom) to determine if a new value has changed with regard to an old value.
然而,事实证明 identical?
对向量和 strings/ints 的行为不同。如果你启动 clj 或 cljs repl,你会看到:
(identical? 1 1)
;; true
(identical? "a" "a")
;; true
(identical? [1] [1])
;; false
(identical? ["a"] ["a"])
;; false
如果您查看 identical?
的作用 here,您会发现它测试其参数是否 相同 object .我认为底层内部数据表示是这样的,在 clojure 中,"a" 始终与自身相同 object,而包含相同值的两个向量彼此不同 object .
确认:对于普通原子而不是试剂原子,我们可以看到字符串标识在原子重置时得以保留,而矢量标识则不然。
(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
它的重新渲染就像它应该基于它的编写方式一样。您正在使用与重置原子相同的函数取消引用原子。我总是把它们分开。
(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]])))