刚开始使用Reagent。我有一个按钮,其#
# summarize the data for the plot
#
trip_freq_plot <- trip_freq %>% group_by(DAY, START_TIME) %>%
summarize(Cnt = sum(Freq))
值导致CPU密集型函数运行;返回需要很长时间。我想更新按钮本身的文本以通知用户可能必须等待,因此我定义了一个指定按钮文本的ratom,然后在函数运行时我:on-click
。
如果我在我的按钮组件功能之外定义了ratom,但是如果我通过reset!
在组件功能中定义了ratom,或者如果我let
在顶层的ratom,则无法工作在组件功能中。也就是说,如果我取消注释下面的第一个注释行,或取消注释reset!
的两行,则按钮文本无法更改。难道我做错了什么?这是预期的行为吗?关于ratoms和DOM更新的一般规则适用于什么?
let
(不相关,但为了澄清:我使用(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..."]
...
技巧described here导致DOM更新,尽管长时间运行的功能会阻止浏览器更新DOM该功能正在运行。)
答案 0 :(得分:2)
您的问题是,每次组件需要(重新)呈现时,您的函数chart-button
都会被调用。例如,在您的本地重置示例中,有人点击该按钮,您的label
将重置为running-label
。试剂检测到此更改并调用您的chart-button
函数,以查看新呈现的按钮应该是什么样的,此时您的第一次重置更改又回来了。 let版本有类似的问题。
有几种方法可以处理Reagent中的本地状态。最简单的方法是从组件返回一个函数而不是向量,如本例所示。
(defn timer-component []
(let [seconds-elapsed (r/atom 0)]
(js/setInterval #(swap! seconds-elapsed inc) 1000)
(fn []
[:div
"Seconds Elapsed: " @seconds-elapsed])))
基本上在Reagent中,您的组件可以是渲染函数,也可以是返回渲染函数的函数。在上面的例子中,我们使用一个闭包来设置一些局部状态,然后返回一个使用该状态的渲染函数。每次seconds-elapsed
递增时,再次调用内部函数并重新呈现组件。
另一种方式更复杂,但可能会帮助你更有意义。您可以使用create-class而不是使用函数作为组件来完全控制组件生命周期。