This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-11-04
Channels
- # announcements (13)
- # beginners (51)
- # boot (3)
- # calva (10)
- # cider (20)
- # clj-kondo (55)
- # cljs-dev (60)
- # clojure (99)
- # clojure-europe (6)
- # clojure-gamedev (9)
- # clojure-italy (19)
- # clojure-nl (7)
- # clojure-spec (20)
- # clojure-uk (42)
- # clojurescript (96)
- # clojurex (37)
- # clojutre (1)
- # cursive (37)
- # data-science (2)
- # datomic (15)
- # defnpodcast (9)
- # duct (7)
- # emacs (6)
- # events (9)
- # fulcro (124)
- # jackdaw (4)
- # jobs (4)
- # leiningen (9)
- # malli (7)
- # mount (3)
- # off-topic (109)
- # other-languages (8)
- # re-frame (39)
- # reagent (4)
- # reitit (6)
- # remote-jobs (2)
- # rewrite-clj (36)
- # ring (4)
- # shadow-cljs (16)
- # spacemacs (16)
- # tools-deps (91)
- # vim (8)
- # yada (2)
Anyone have an idea of best practice for dispatching an event (effect) every time a subscription changes?
What’s the context?
@manutter51 I'm building an electron app and I want to update the "badge count" on the dock icon in response to a subscription (`:cards/due-today-count`)
I might write a component that sets the badge count declaratively. Eg somewhere in your app, you have [badge-count @(subscribe ...)]
. The badge-count
component can use :component-did-mount & :component-did-update to fire the necessary side effects - these are implementation details hidden behind a declarative API, like how React hides DOM manipulation. You can then treat it as ‘just another view,’ even though you are displaying something outside the react tree. I use an approach like this for setting things like window.document.title
Updating the app's icon badge count requires sending an API call to the electron process
Ok, so probably there’s some event that’s updating the app-db
value that’s feeding the subscription, right?
:thinking_face:
you probably shouldn't dispatch a re-frame event from a subscription, but you can do side-effects based on a subscription by using add-watch
or a reagent reaction
How about run!
? http://reagent-project.github.io/docs/master/reagent.ratom.html#var-run.21
@lilactown is add-watch
part of the reagent api?
maybe it would be fine to dispatch a re-frame event, but if you update the db it might go into an infinite loop if you're not careful
reactions and ratoms implement the protocols necessary to use add-watch
, which is in the core library, I believe
Another thing that can work if you're willing to add it multiple places (and maybe restructure a little bit): https://github.com/day8/re-frame/blob/master/src/re_frame/std_interceptors.cljc#L319-L324
run!
seems appropriate for this use case. Would I just call that in e.g. the top level component? Feels odd putting something like that in a component
it depends how parameterized your component is. It if it is effectively "global", then at the top level is fine. Sometimes I've done it via "track!" (IIRC), which is similar, but can be disposed in component-will-unmount, so it is appropriate if the subscription requires parameters.
I wouldn’t put it in a component. I would put it in my function that starts the app, or maybe even a defonce
to prevent it from getting executed multiple times
with-let
can also be used for this: http://reagent-project.github.io/docs/master/reagent.ratom.html#var-with-let
Documentation for it in this blog post: https://reagent-project.github.io/news/news060-alpha.html
I wouldn't do it in with-let
because you still might re-mount the component when you restart the app with some changes
that's why I would move it outside of a component entirely, probably something like:
(defonce update-badge-count (run! ...))
you can do it manually (using add-watch / remove-watch or a reaction directly) or you just don't care
this is "fire off arbitrary side effect based on a subscription" which shouldn't involve reagent/react/DOM at all
Yeah, I think not having it in a component makes sense, because it's not a view concern really
in my case, usually there is some kind of scope (and therefore component) for which it makes sense to have a thing running, and I always regret not doing something like that, but maybe it is different for you
That's a good point, but I think in my case it makes sense for this thing to always run as long as the app i open
I might write a component that sets the badge count declaratively. Eg somewhere in your app, you have [badge-count @(subscribe ...)]
. The badge-count
component can use :component-did-mount & :component-did-update to fire the necessary side effects - these are implementation details hidden behind a declarative API, like how React hides DOM manipulation. You can then treat it as ‘just another view,’ even though you are displaying something outside the react tree. I use an approach like this for setting things like window.document.title