This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-05
Channels
- # announcements (1)
- # babashka (5)
- # beginners (151)
- # calva (43)
- # clj-kondo (23)
- # cljdoc (1)
- # cljs-dev (6)
- # cljsrn (10)
- # clojure (60)
- # clojure-australia (1)
- # clojure-europe (26)
- # clojure-gamedev (14)
- # clojure-nl (1)
- # clojure-spec (10)
- # clojure-uk (80)
- # clojurescript (66)
- # clojureverse-ops (4)
- # community-development (7)
- # conjure (8)
- # datomic (15)
- # deps-new (1)
- # docker (27)
- # emacs (2)
- # fulcro (13)
- # honeysql (13)
- # java (5)
- # jobs-discuss (43)
- # lsp (121)
- # luminus (13)
- # malli (1)
- # off-topic (73)
- # pathom (12)
- # polylith (29)
- # practicalli (4)
- # re-frame (35)
- # reagent (44)
- # remote-jobs (5)
- # rewrite-clj (2)
- # sci (7)
- # shadow-cljs (125)
- # sql (4)
- # tools-deps (9)
- # xtdb (5)
quick question:
I got a sub :my/sub
that has some logic in it.
I noticed that the logic gets executed every time `(subscribe [:my/sub]) is called.
But I’d prefer the logic to be executed only when input data changed (the sub depends on other subs :<- [:other-sub/i-want-to-be-the-triggerer-for-the-logic]
what’s the best way to deal with this?
same place
I mean… in the view
it’s a push/pull problem. I kinda discovered that reframe is a pull thingy….I am used to push thingy
> Is it in a JS event handler? no. in a let block.
so every time the view is rendered, it calls subscribe and executes the logic
I’d like that logic to execute only when it’s “parent” subs changed
Thanks.
otherwise…it means that every time that view is mounted, it would run every logic, of every sub in the graph
It doesn't happen on my end. How do you check - via code reload or via some data change that re-renders the view?
• view A subscribes to :a/sub first time, so it runs the logic
• view A is destroyed, and now view B is shown
• you click on a button, and view B is destroyed, so view A gets rendered again
• view A has a subscribe
to :a/sub and that gets ‘processed’ again, even though it’s input subs did not change
I managed to “fix it” by using memoize
but that does not sound like an amazing way to do things.
A better way to fix it would be to lift that sub to a common parent of A and B and just pass the value down.
> A better way to fix it would be to lift that sub to a common parent of A and B and just pass the value down. but that would make me move logic that belongs in A somewhere else.
would it really be a memory leak? as soon input changes…it will GC prev value and substitute it? how would it differ from having an atom and checking it before running the logic?
> but that would make me move logic that belongs in A somewhere else.
At the same time, A and B clearly share some functionality. So another potential way to fix it would be to make a single component out of them or to wrap them together in something that would deal with that common logic.
> would it really be a memory leak?
The core implementation of memoize
never releases the cached data.
There are, however, alternative implementations. E.g. this https://github.com/ptaoussanis/encore/blob/master/src/taoensso/encore.cljc#L1981
> The core implementation of `memoize` never releases the cached data. It might be fine if you have a few known inputs and the overall inputs+data size is insignificant. It is absolutely not fine if you use e.g. mouse coordinates or current time as an input - the cache will just keep on growing.
it takes 2 maps. quite large…but they do not change ever.
Should be fine then. But yeah, the maps will also stay in memory for as long as that def
exists, or whatever you end up using to store the result of memoize
.
those maps are already in the reframe-db…so its not the maps, but their reference, am I mistaken?
Ah, sure! No problem then. As long as they don't change.
Keep in mind that that premise might change in the future. And then memoize
might potentially become a very unpleasant issue to encounter and debug.
Also note that, depending on your computations in the sub fn, memoize
might actually be slower than doing the actual computation.
sure. I was reading memoize from core. it keeps all states.. now I got what you meant.
the computation itself is not expensive. annoyance is that is not deterministic. it’s got a shuffle
there.
so…yeah.
will look into the other implementation. thanks for the tips!
Oh, hold on. A shuffle
sounds interesting when you want to end up having a determined result for some particular input.
What I think you should do instead of all the memoize
or implicit sub caching shenanigans then is to compute the data on input change outside of the subs and store it in the app-db. And then use subs to simply extract that data - that's it.
It can easily be done with a global interceptor that watches for changes at some particular path in app-db and assocs a new value at some different path when it happens.
The exact same strategy you would use when a view needs to retrieve some data from a server based on some existing data in app-db. But there it would be http-get
while you have shuffle
.
before, this shuffling logic was at the http level, and it was being “cached” in the reframe db. but I that logic should not live there… it does not belong in there. it makes the code confusing. a simple
(defn memo [f]
(let [empty {}
!args (atom empty)
!result (atom empty)]
(fn [& args]
(if (= @!args args)
@!result)
(do (reset! !args args)
(reset! !result (apply f args))))))
should do what I need alright.