re-frame

https://github.com/Day8/re-frame/blob/master/docs/README.md https://github.com/Day8/re-frame/blob/master/docs/External-Resources.md
lispers-anonymous 2020-09-19T21:06:01.008300Z

I am trying to see if it is possible to use a subscription in an event handler without creating a memory leak, while also avoiding the need to dispose of reactions created by re-frame.core/subscribe like is done in this example: https://github.com/den1k/re-frame-utils/blob/master/src/vimsical/re_frame/cofx/inject.cljc Here is my implementation using coeffects. I am not super familiar with the re-frame code base so I was wondering if anyone could foresee any issues with what I'm trying to do.

(rf/reg-cofx
 ::sub
 (fn [{:keys [db] :as cofx} [operation :as query-v]]
   (if-let [cached-reaction (re-frame.subs/cache-lookup query-v)]
     (assoc cofx operation @cached-reaction)
     (if-let [sub-handler (re-frame.registrar/get-handler :sub operation true)]
       (let [reaction (sub-handler db query-v)]
         (assoc cofx operation @reaction))
       cofx))))
The basic idea is to check the subscription cache and take advantage of it if I can, and if not just run the subscription directly. Does anyone have thoughts on this? Is avoiding the dispose! function a worthy effort?

p-himik 2020-09-19T21:13:23.008600Z

The sub mentioned by query-v can have other subs as its input signals. In that case, it will use subscribe and thus will create a memory leak.

p-himik 2020-09-19T21:14:26.008800Z

Apart from that, I don't see any pitfalls. Well, except that you're using private API.

lispers-anonymous 2020-09-19T21:22:24.009Z

Would that mean the memory leak issue is also present in the code I referenced here: https://github.com/den1k/re-frame-utils/blob/master/src/vimsical/re_frame/cofx/inject.cljc? If so, does that make dispose! unavoidable?

lispers-anonymous 2020-09-19T21:23:19.009200Z

And I'm alright with the risk of using a private API, as it stands now I'm not using this anywhere. Glad you pointed that out though.

p-himik 2020-09-19T21:26:01.009400Z

That code calls dispose!, and I believe it will destroy all signal subs if they're not used in any view or other sub because they would not have any watches after the main sub is destroyed. But I may be wrong, so you should check that.

p-himik 2020-09-19T21:26:54.009600Z

> If so, does that make dispose! unavoidable? With the way subs are written now in re-frame, yes.

lispers-anonymous 2020-09-19T21:28:08.009800Z

That's super helpful, I'll investigate. Thanks again for answering my questions!

p-himik 2020-09-19T21:29:04.010Z

You can create your own subs mechanism that would work on top of re-frame. The only thing required for you to be able to run subs in any places is to be able to extract the unwrapped sub function, along with all its input signals. This way, it would be possible to traverse the sub tree and call each function (and maybe looking in the cache each time just in case the value is already there).

p-himik 2020-09-19T21:31:36.010200Z

Although, cache lookups will create a possibility of race conditions. Or maybe that's a wrong term in this case. If you e.g. (let [db (assoc db :a 1)] ...) and feed that new db to such a raw sub function, any cache lookups will use the old db, without {:a 1}. Tricky stuff.

lispers-anonymous 2020-09-19T21:35:30.010400Z

That seems do-able for handling input signals. Where might the invalid cache scenario come up? I wouldn't plan on making changes to the DB anywhere until the subscription co-effect is complete.

p-himik 2020-09-19T21:47:00.010700Z

Another coeffect, for example.

lispers-anonymous 2020-09-19T21:56:49.010900Z

Oh I see. That does make sense. You've given me a lot to think about then. I'm unsure if I can avoid that outdated cache issue with the data I am given.