reagent

shaunlebron 2026-03-24T22:31:27.190949Z

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?

shaunlebron 2026-03-26T16:25:24.597559Z

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

p-himik 2026-03-26T16:48:48.447329Z

memoize retains the cache indefinitely, prone to memory leaks.

shaunlebron 2026-03-26T16:49:21.210789Z

oh that is good to know

shaunlebron 2026-03-26T16:50:02.826469Z

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

shaunlebron 2026-03-26T16:53:16.295369Z

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

p-himik 2026-03-26T16:59:01.220679Z

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

👍 1
shaunlebron 2026-03-26T17:09:35.701259Z

local memoized functions are like lazy maps, pretty cool

shaunlebron 2026-03-25T22:28:09.598449Z

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

shaunlebron 2026-03-25T22:30:36.086559Z

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

p-himik 2026-03-25T22:33:19.593259Z

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!

shaunlebron 2026-03-26T02:26:19.156239Z

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

p-himik 2026-03-24T22:49:58.065859Z

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
p-himik 2026-03-24T22:57:00.611099Z

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

shaunlebron 2026-03-24T23:04:39.250499Z

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

shaunlebron 2026-03-24T23:06:41.408579Z

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

shaunlebron 2026-03-24T23:12:28.929459Z

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

shaunlebron 2026-03-24T23:18:28.721859Z

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

shaunlebron 2026-03-24T23:23:05.904869Z

looks like the flush worked

shaunlebron 2026-03-24T23:46:54.140179Z

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