使用Clojure / Reagent制作一个简单的倒数计时器

时间:2015-05-16 20:34:56

标签: clojure reagent

我正在尝试使用几乎没有经验的Clojure和Reagent,尝试制作一个简单的计时器。

(defn reset-component [t]
  [:input {:type "button" :value "Reset"
           :on-click #(reset! t 60)}])

(defn countdown-component []
  (let [seconds-left (atom 60)]
    (fn []
      (js/setTimeout #(swap! seconds-left dec) 1000)
      [:div.timer
        [:div "Time Remaining: " (show-time @seconds-left)]
        [reset-component seconds-left]])))

计时器倒计时似乎正常,直到我按下重置按钮。之后,计时器开始倒计时两倍。每次按下重置按钮,它都会更快地倒计时。

如何让计时器在页面加载时自动倒计时,但在点击重置按钮时不会倒计时更快?

4 个答案:

答案 0 :(得分:3)

取消引用reset-component中的秒数会触发倒计时组件的重新呈现,该组件会将另一个递减器功能附加到倒计时组件。

答案 1 :(得分:2)

为了将来参考,reagent 0.6.0 +带有一个新的with-let宏,对于需要正确"销毁"的内容非常有用,例如{{1} } / setInterval

clearInterval

这是该功能的官方anouncement

请注意,从渲染函数调用(defn countdown-component [] (r/with-let [seconds-left (r/atom 60) timer-fn (js/setInterval #(swap! seconds-left dec) 1000)] [:div.timer [:div "Time Remaining: " (str @seconds-left)]] (finally (js/clearInterval timer-fn)))) 也可以,但它不被视为好习惯。 (例如https://clojurians.slack.com/archives/C0620C0C8/p1495568238109060

答案 2 :(得分:1)

我发现的解决方案是在组件函数之前使用setInterval而不是在组件函数中使用setTimeout

(defn reset-component [seconds]
  [:input {:type "button" :value "Reset"
           :on-click #(reset! seconds 60)}])

(defn countdown-component []
  (let [seconds-left (atom 60)]
    (js/setInterval #(swap! seconds-left dec) 1000)
    (fn []
      [:div.timer
       [:div "Time Remaining: " @seconds-left]
       [reset-component seconds-left]])))

答案 3 :(得分:0)

你可能想要这个:

(defn reset-component [t]
  [:input {:type "button" :value "Reset"
           :on-click #(reset! t 60)}])

(defn countdown-component []
  (let [seconds-left (atom 60)]
    (js/setInterval #(swap! seconds-left dec) 1000)
    (fn []  
      [:div.timer
        [:div "Time Remaining: " (show-time @seconds-left)]
        [reset-component seconds-left]])))

请注意,现在调用setInterval仅在组件初始化时发生,而不是在呈现阶段发生。