【问题标题】:Which changes to clojurescript atoms cause reagent components to re-render?clojurescript 原子的哪些更改会导致试剂组件重新呈现?
【发布时间】:2020-03-10 02:52:56
【问题描述】:

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

【问题讨论】:

  • 我不在可以测试它的设置附近,但请尝试在get-real-size 中记录计算的大小。我的猜测是它在不断变化。那是因为每次它获得自己的大小并显示不同的值时,宽度都会发生变化,因此它会重新渲染,获得一个新的 ref,具有新的大小,具有不同的宽度......
  • 不,我也猜到了。函数为 dummy 时也一样:(defn get-real-size [_] [0 0])

标签: clojure clojurescript reagent


【解决方案1】:

我想我对为什么向量的行为不同于字符串/数字有一个答案。当identical? 在新旧值之间返回 false 时,Reagent 将试剂原子计为“已更改”(并因此更新依赖于它的组件)。看到副标题“改变了吗?”在this tutorial

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

然而,事实证明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

【讨论】:

  • 是的,这是正确的答案。根据github.com/reagent-project/reagent/blob/master/…,我希望Reagent 在这种情况下使用相等,但0.6.0-rc 表现出相同的行为。你认为这是一个错误,还是反应和随机数之间的故意差异?
【解决方案2】:

您可以通过not= 检查解决该问题:

                (fn [el]
                  (when el
                    (let [s (get-real-size el)]
                      (when (not= s @size)
                        (reset! size s)))))

我不确定为什么向量应该不同于其他值。

【讨论】:

    【解决方案3】:

    它的重新渲染就像它应该基于它的编写方式一样。您在重置原子时在同一函数中取消引用原子。我总是把它们分开。

    (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]])))
    

    【讨论】:

      猜你喜欢
      • 2016-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-26
      • 1970-01-01
      • 2020-06-27
      • 1970-01-01
      相关资源
      最近更新 更多