Local reagent atom won't update when global ratom change

396 views Asked by At

Let's say I have a component defined like this:

(defn test-comp
  [timespan-ratom]
  (let [[timespan-lower timespan-upper] @timespan-ratom]
    (fn []
      [:div.row (str "Testing" timespan-lower timespan-upper)])))

timespan-ratom is defined globally in the component that instantiates test-comp like this:

(def timespan-ratom (ratom nil))

It's instantiated like this:

[test-comp timespan-ratom]

The first time the timespan-ratom is used to create test-comp "Testing" will be printed with the correct timespan-lower and timespan-upper value. But when the timespan-ratom is reset (reset!) the values are not updated in the test-comp component? Why is this?

It works when I change the function to this:

(defn test-comp
  [timespan-ratom]
    (fn []
      [:div.row (str "Testing" (first @timespan-ratom) (second @timespan-ratom))]))

Now the reason why I can't simply do like this is that in my actual production code I have local ratom that is dependent on the value of the timespan-ratom:

(defn test-comp
  [timespan-ratom]
  (let [[timespan-lower timespan-upper] @timespan-ratom
        selected-time (ratom timespan-upper)]
    (fn []
      ,,,)))

I.e. the initial value of selected-time should be the timespan-upper value defined by the timespan-ratom. The selected-time ratom is then changed locally from the test-comp component.

How can I solve this?

1

There are 1 answers

4
Michiel Borkent On BEST ANSWER

Remove the inner function nesting from test-comp:

(defn test-comp
  [timespan-ratom]
  (let [[timespan-lower timespan-upper] @timespan-ratom]
    [:div.row (str "Testing" timespan-lower timespan-upper)]))

When you use an inner function with no arguments, the component can never receive the updated ratom, so it will forever hold on to the first value it got from the ratom on the first render. Also, you don't need the inner function here, because you don't have any local state.

If you do have local state (some state that needs to be remembered over the lifetime of the component), update your component so the inner function has the same arguments as the outer function and dereference the atom in the inner function:

(defn test-comp
  [ratom]
  (let [x "local-state"]
    (fn [ratom]
      (let [v @ratom]
        [:div x v]))))