Reputation: 3326
When perusing this post on Reagent with Clojurescript I experimented with different ways to implement the timer-component
component. My first attempt, however, did not work:
(defn timer-component []
(fn []
(let [seconds-elapsed (r/atom 0)]
(js/setTimeout #(swap! seconds-elapsed inc) 1000)
[:p (str "Expired time: " @seconds-elapsed)])))
As a debug log statement reveals the timer is still called regularly and the seconds-elapsed
variable is still updated correctly. The display, however, is not updated and the component always shows "Expired time: 0".
Compared to the code example in the blog post my component interchanges the fn
and the let
declarations and this modification seems to prevent proper display, but not proper updates of the component. My expectation was that either the component is both updated and displayed properly or neither updates nor displays.
My question is why does this happen? Is this a bug in Reagent or some misuse of the API on my part?
Upvotes: 0
Views: 323
Reputation: 1372
You are always seeing the same value, because the inner anonymous function is being called for every (re-)render. Thus, seconds-elapsed
is being bound again and again to a new atom with value 0. This is not a bug, but how Reagent is supposed to work.
Your component is "Form-2" and should declare its local state in the outer function timer-component
, which is called only once per component. Re-frame documentation explains different forms of Reagent components nicely.
Re-frame docs add comments to the example in the Reagent tutorial, which may help to clarify:
(defn timer-component []
(let [seconds-elapsed (reagent/atom 0)] ;; setup, and local state
(fn [] ;; inner, render function is returned
(js/setTimeout #(swap! seconds-elapsed inc) 1000)
[:div "Seconds Elapsed: " @seconds-elapsed])))
Upvotes: 2