Fork me on GitHub
Pepijn de Vos09:03:53

Would be nice if you could ratelimit/debounce reactions/track functions


As a workaround, you can instead ratelimit/debounce functions that reset!/`swap!` ratoms that reactions/tracks depend on.

Pepijn de Vos09:03:14

Not really. I want to update the UI instantly, but not run expensive track functions every time. So far it's not a real issue, but it'd be something potentially nice to have.


You can switch from reaction/track to run! + ratom with a debounced function that resets that ratom.

Pepijn de Vos09:03:03

that would work!

Pepijn de Vos10:03:22

Nope it doesn't. debounce uses settimeout so it doesn't see the function as using the ratom

Pepijn de Vos10:03:56

ratelimit might though, because that also calls the function immediately


Wait. debounce isn't supposed to monitor the ratom. It's supposed to change that. run! can work on any function, as long as there are other ratoms outside it.


What code did you come up with?


I meant something like this:

  (let [a @my-ratom-a
        b @my-ratom-b]
    (debounced-function a b)))

Pepijn de Vos11:03:50

Ah you want to do (fn [] @ratom (debounce f) while I was doing (debounce (fn [] @ratom))


Yeah, the latter can't work of course, exactly for the reason you described.

Pepijn de Vos11:03:02

Hm, does reagent have a defined/controllable evaluation order? Say I have

(def a (r/atom {})
(def b (r/track #(foo @a)))
(def c (r/track #(bar @a @b)))
It would be unfortunate if it'd evaluate c first, then b and then c again when a changes.


When a ratom changes, it marks all its watchers, including reactions and tracks, as dirty. Any dirty reaction will be recomputed when its value is requested. So in the above, c will not use the old value of b - it will recompute it when a is changed.


You refer in general to the issue of "glitches". I do not know if it now appears in our Slack history, but a few years ago I posted an example that demonstrated that Reagent is indeed susceptible to "glitches". As you note, this is problematic in that c will transiently take on an inconsistent value, rectified when the second signal retriggers evaluation and c then takes on a value consistent with a as a direct value and via b.


Note that it might not be the case when you're using reactive functionality outside of a reactive context. People have mentioned before that Reagent is susceptible to such issues - but so far every single piece of code that I've seen that was able to reproduce it was run outside of a reactive context. @U0PUGPSFR I found some of your old messages, and they seem to have used a non-reactive context as well. I.e. there was no view in the end. REPL sessions aren't enough to test Reagent reactivity. You need a proper UI setup for that, with some view component at the end.


It sounds as if you are saying the view logic manages to wait in some fashion for the reactive flow to converge on consistent values for the view rendering. That sounds reasonable since the rendering is tightly controlled. But then that means Reagent reactivity is not generally useful, eg for side effects in which XHR requests might be dispatched. I think both re-frame and Matrix demonstrate that a glitch-free reactive system can quite usefully dispatch interesting side effects, which would not be the case with Reagent.