reagent 2026-03-24

if I create a reaction in a with-let binding, it looks like I have to dispose it in the finally block. perhaps the macro should do this for us?

you were right, I can just use memoize instead of with-let and track if I already have a function that returns a reaction

memoize retains the cache indefinitely, prone to memory leaks.

oh that is good to know

I assumed they would be cached to the locally scoped function and would be gc'd with it

looking at cljs.core/memoize, it looks like the mem atom can be gc'd if nothing uses the returned function anymore

Ah yeah, that's true. I assumed you had something like (def f (memoize (...))).

👍 1

local memoized functions are like lazy maps, pretty cool

finalized code for detecting intermediate changes inside a render batch, with examples I used to test: https://gist.github.com/shaunlebron/d6a681ce74f46cf1b23b2b7f07f14759

test-inner-flashes has a weird pattern of nested with-lets and track, but it seems to work, based on what I understood from the mouse-pos example, and things seem to dispose correctly. thanks p-himik for the insight on how they dispose

Don't have time right now to delve deeper into it, but it surely looks like some over-engineering. ;) A nested with-let, an immediately @'ed track... I could be wrong though!

Hmm, this is also what the mouse-pos demo in the docs was doing. Maybe there's a simpler way

If you create a reaction and do nothing else with it, no need to dispose! of it - there's nothing to dispose of. If you also @ that reaction in that very component, the reaction will be registered with that component. When the component unmounts, the reaction will gets its watchers updated. If there are no watchers, the reaction will be disposed of automatically.

🙏 1

Just tested it - yep, seems to work that way.

hmm, I’m using a run!, might have to dispose that manually or rethink why I reached for that

trying to make a "flash" reaction:

(defn flash
  "A reaction that returns any logical true result of pred whenever r* changes.
   The reaction’s value resets to nil after `ms` milliseconds, unless interrupted by another logical true r*."
  [r* pred ms]
  (let [flash-val* (r/atom nil)
        timeout* (volatile! nil)]
    (ra/run!
      (when-some [v (pred @r*)]
        (reset! flash-val* v)
        (js/clearTimeout @timeout*)
        (->> (js/setTimeout #(reset! flash-val* nil) ms)
             (vreset! timeout*))))
    flash-val*))

another problem is that we sometimes receive two events in the same rendering frame that update our state, and our view misses the intermediate state, so we can’t even use a "flash" reaction like this because I think updates are batched

maybe I can call add-watch on our state ratom and r/flush when certain critical values change

looks like the flush worked

this seems to dispose now:

(defn flash
  "A reaction that returns any logical true result of pred whenever r* changes.
   The reaction’s value resets to nil after `ms` milliseconds, unless interrupted by another logical true r*."
  [r* pred ms]
  (let [flash-val* (r/atom nil)
        timeout* (volatile! nil)
        pred* (ra/make-reaction
                (fn []
                  (when-some [v (pred @r*)]
                    (reset! flash-val* v)
                    (js/clearTimeout @timeout*)
                    (->> (js/setTimeout #(reset! flash-val* nil) ms)
                         (vreset! timeout*))
                    v))
                :on-dispose (fn [] (println "pred* disposing"))
                )]
    (ra/make-reaction
      (fn []
        @pred*
        @flash-val*)
      :on-dispose (fn [] (println "flash disposing")))))