Clojurescript 组件can'中指定的Ratom;你不更新那个组件吗?

Clojurescript 组件can'中指定的Ratom;你不更新那个组件吗?,clojurescript,reagent,Clojurescript,Reagent,从试剂开始。我有一个按钮,它的:单击值会导致CPU密集型功能运行;要花很长时间才能回来。我想更新按钮本身的文本以通知用户可能需要等待,因此我定义了一个ratom来指定按钮文本,然后我reset函数运行时的ratom 如果我在我的按钮组件功能外定义ratom,则此功能有效,但如果我通过let在组件功能内定义ratom,或如果我重置,则此功能无效组件功能中顶层的ratom。也就是说,如果我取消注释下面的第一行注释,或者取消注释let的两行注释,则按钮文本无法更改。我做错什么了吗?这是预期的行为吗?关

从试剂开始。我有一个按钮,它的
:单击
值会导致CPU密集型功能运行;要花很长时间才能回来。我想更新按钮本身的文本以通知用户可能需要等待,因此我定义了一个ratom来指定按钮文本,然后我
reset函数运行时的ratom

如果我在我的按钮组件功能外定义ratom,则此功能有效,但如果我通过
let
在组件功能内定义ratom,或如果我
重置,则此功能无效组件功能中顶层的ratom。也就是说,如果我取消注释下面的第一行注释,或者取消注释
let
的两行注释,则按钮文本无法更改。我做错什么了吗?这是预期的行为吗?关于ratoms和DOM更新,这里适用的一般规则是什么

(def label (reagent.core/atom "Make chart"))

(defn chart-button
  [normal-label running-label]
;  (reset! label normal-label)                   ; reset globally-defined ratom
;  (let [label (reagent.core/atom normal-label)] ; use local ratom
    [:button {:on-click (fn []
                          (reset! label running-label)
                          (js/setTimeout (fn []
                                            (cpu-intensive-function)
                                            (reset! label normal-label))
                                         10))
              }
     @label] ;)
)

...
[chart-button "make chart" "running..."]
...

(不相关,但需要澄清:我使用
setTimeout
技巧使DOM更新,尽管长时间运行的函数会阻止浏览器在函数运行时更新DOM。)

这里的问题是,每次需要(重新)渲染组件时,都会调用函数
图表按钮。例如,在本地重置示例中,有人单击按钮,您的
标签
将重置为
运行标签
。试剂检测到这一变化并调用
图表按钮
功能,查看新呈现的按钮应该是什么样子,此时您的第一次重置变化又回来了。let版本也有类似的问题

有两种方法可以处理试剂中的局部状态。最简单的方法是从组件返回函数,而不是向量,如本例所示

(defn timer-component []
  (let [seconds-elapsed (r/atom 0)]
    (js/setInterval #(swap! seconds-elapsed inc) 1000)
    (fn []
      [:div
       "Seconds Elapsed: " @seconds-elapsed])))
基本上,在试剂中,组件可以是渲染函数,也可以是返回渲染函数的函数。在上述情况下,我们使用闭包来设置一些局部状态,然后返回使用该状态的渲染函数。每次
经过的秒数
增加时,将再次调用内部函数并重新加载组件


另一种方法更为复杂,但可能会帮助您从中获得更多的意义。通过使用函数而不是将函数用作组件,您可以完全控制组件的生命周期。

您的问题在于,每次需要(重新)呈现组件时,都会调用函数
图表按钮。例如,在本地重置示例中,有人单击按钮,您的
标签
将重置为
运行标签
。试剂检测到这一变化并调用
图表按钮
功能,查看新呈现的按钮应该是什么样子,此时您的第一次重置变化又回来了。let版本也有类似的问题

有两种方法可以处理试剂中的局部状态。最简单的方法是从组件返回函数,而不是向量,如本例所示

(defn timer-component []
  (let [seconds-elapsed (r/atom 0)]
    (js/setInterval #(swap! seconds-elapsed inc) 1000)
    (fn []
      [:div
       "Seconds Elapsed: " @seconds-elapsed])))
基本上,在试剂中,组件可以是渲染函数,也可以是返回渲染函数的函数。在上述情况下,我们使用闭包来设置一些局部状态,然后返回使用该状态的渲染函数。每次
经过的秒数
增加时,将再次调用内部函数并重新加载组件

另一种方法更为复杂,但可能会帮助您从中获得更多的意义。您可以通过使用而不是使用功能作为组件来完全控制组件生命周期。

非常感谢--非常清楚的诊断和解释。现在一切都有意义了。(也许我早该知道。我读过,但没有理解。)非常感谢——非常清楚的诊断和解释。现在一切都有意义了。(也许我早该知道。我读过,但没有理解。)