Fork me on GitHub
#re-frame
<
2022-06-27
>
romdoq11:06:44

Is there any guidance/advice/tools for composing single events from functionality in multiple independent namespaces? One could, for example:

(reg-event-fx 
  ::do-stuff
  (fn [coeffects event]
    {:fx [ [:dispatch [::foo/update-thing :potato]]
           [:dispatch [::bar/herp-the-derp :derpderp]]
           [:dispatch [::routing/go-to-page :blah]]
However these will all take place at some uncertain future time, and not necessarily at the same time (especially if the sub-dispatches also call :dispatch, etc.), which can lead to unresponsive UIs, or non-atomic UI updates (eg. a brief flash of old data before the appdb is updated by another event) - neither of which is desirable IMO. What I'd like to be able to do is perform all necessary actions in the processing of a single event, something like:
(reg-event-fx 
  ::do-stuff
  (fn [coeffects event]
    (fx-> coeffects
      (foo/update-thing :potato)
      (bar/herp-the-derp :derpderp)
      (routing/go-to-page :blah)
Which on the surface seems like the functions could be fairly straight-forward, but I'm not so sure given that, among other concerns, each function may want to introduce its own interceptors? :thinking_face: Anyone have any insight?

p-himik11:06:41

The function composition approach is the way to do. Each function will be just that - a function. As such, they won't care or even know about interceptors.

lassemaatta12:06:18

I just recently wrote something like. I'm not at liberty to share the code, but it was simple and fun to implement 🙂 Plus my implementation was most likely buggy and awful. You take the cofx map and reduce over a collection of functions, which each take the latest cofx and return a map of effects. And then you just make sure the db in cofx is updated at each iteration. (but we didn't use per-event interceptors etc)

romdoq12:06:33

@U2FRKM4TW My point about interceptors is that, if a pure function expects a coeffect which is supplied by an interceptor, the composing event needs to know that and make sure to apply that interceptor itself - which essentially requires the composing event to know about and be kept in sync with an implementation detail. 😕

romdoq12:06:57

@U0178V2SLAY do you return the coeffects map from each function? I feel that that could lead to unexpected/hidden issues, since coeffects != effects? :thinking_face:

lassemaatta12:06:40

no, the reducing function takes the returned fx and checks if there's a db inside and then updates the cofx if necessary

1
p-himik12:06:47

That is true, so far there's no any easy mechanism to overcome that. Should be relatively easy to make one though, it you make an event into something first-class. I myself use like 3-5 interceptors in any given project, so motivation to make something like that is nonexistent.

romdoq12:06:42

Yeah, parts of our codebase use a bunch of sub-injection interceptors, so we have quite a few to deal with 😅

p-himik12:06:11

Right, I never use sub injection myself - I always simply access the values from the DB.

emccue18:06:58

@UD9ECLVDL I always use the :db and :fx forms and then i have a mechanism for composing events that take db and return db and fx

emccue18:06:22

for the interceptors thing...yeah mostly avoid them

emccue18:06:39

only exception has been for "the current time", but even that isn't strictly needed