1

我正在尝试几乎没有经验的 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

4 回答 4

5

在 reset-component 中取消引用 seconds-left 会触发 countdown 组件的重新渲染,该组件将另一个 decrementer 函数附加到您的 countdown-component。

于 2015-05-16T22:18:35.040 回答
4

为了将来参考,reagent0.6.0+ 带有一个新with-let宏,对于需要适当“破坏”的东西非常有用,例如setInterval/ clearInterval

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

这是该功能的官方公告

请注意,setTimeout从 render 函数中调用也可以,但这并不是一种好的做法。(例如https://clojurians.slack.com/archives/C0620C0C8/p1495568238109060

于 2017-05-23T21:23:59.280 回答
2

我找到的解决方案是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]])))
于 2015-06-04T23:15:55.863 回答
1

你可能想要这个:

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

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

于 2015-06-03T17:49:18.967 回答