re-frame

rende11 2024-06-09T11:59:01.873139Z

Hi, is there any way to shorten such a record or make it more linear? I would like it to be clear which chain of events is called without viewing all the events one by one.

(rf/reg-event-fx
   :evt/run
   (fn [_ _]
     {:fx [[:dispatch [:evt/one]]]}))

  (rf/reg-event-fx
   :evt/one
   (fn [_ _]
     (let [res (+ 2 2)]
       {:fx [[:dispatch [:evt/two res]]]})))

  (rf/reg-event-fx
   :evt/two
   (fn [_ [_ value]]
     (let [res (+ value 10)]
       {:fx [[:dispatch [:evt/three res]]]})))

  (rf/reg-event-fx
   :evt/three
   (fn [_ [_ value]]
     {:fx [[:dispatch [:success value]]]}))

p-himik 2024-06-09T12:07:27.347509Z

The best approach relies on a bit of discipline where all "util-level", just reusable events, or maybe even all events are implemented with reg-event-fx that you use on a function defined separately. In addition, the :dispatch effect and its cousins are not used at all and instead the separately defined handlers are used. You may or may not have a wrapper to avoid having to pass a vector of arguments instead of the arguments themselves. Your code can be then rewritten as:

(defn success [cofx value]
  ...)

(defn three [cofx value]
  (success cofx value))

(defn two [cofx value]
  (let [res (+ value 10)]
    (three cofx res)))

(defn one [cofx]
  (let [res (+ 2 2)]
    (two cofx res)))

(defn run [cofx]
  (one cofx))

(rf/reg-event-fx :evt/run (fn [cofx _] (run cofx)))
(rf/reg-event-fx :evt/one (fn [cofx _] (one cofx)))
(rf/reg-event-fx :evt/two (fn [cofx [_ value]] (two cofx value)))
(rf/reg-event-fx :evt/three (fn [cofx [_ value]] (three cofx value)))
(rf/reg-event-fx :success (fn [cofx [_ value]] (success cofx value)))
It then becomes a plain chain of functions. And if some event is not used as an event, you don't need to register it at all - it's just a plain function.

1
rende11 2024-06-10T15:25:27.411449Z

@p-himik Sorry, It's not clear for me - how I can avoid of using :dispatch?

p-himik 2024-06-10T15:26:20.825859Z

My code above doesn't use :dispatch.

p-himik 2024-06-10T15:26:52.011329Z

You will have to use dispatch to initiate events as a consequence of a user/browser action. But it's not :dispatch.

rende11 2024-06-10T15:59:01.734029Z

Oh, I think I figured, it would work when we want to pass some kind of value through a chain of events.

p-himik 2024-06-10T16:02:45.771189Z

It would work in any case because it ends up being just calling regular functions. The only potential issues if some event handlers require injecting extra co-effects. That can probably be handled in some clever way but such a situation is quite rare in my experience to be bothered enough to think about it.

rende11 2024-06-10T16:12:29.868079Z

Another example - Here is 3 operations which one should be executed sequentially, but some on then(2) consists of chains of events. I wan't to achive this order of events: :generate-password :store-password :generate-account-data :store-account-data :create-account Some of them use the results of previous operations I have only one opportunity to put them one into another?

(rf/reg-event-fx
   :evt/run-workflow
   (fn []
     {:fx [[:dispatch [:generate-password {:on-success [:dispatch [:store-password]]}]]
           [:dispatch [:generate-account-data {:on-success [:dispatch [:store-account-data]]}]]
           [:dispatch [:create-account]]]}))

p-himik 2024-06-10T16:31:32.468349Z

Same exact principle - extract the handlers into their own functions and call those functions directly. Use reg-event-* functions mainly for user- or browser-triggered events.

rende11 2024-06-10T19:35:22.628129Z

But these events produces different effects, and in this case they are should be merged somehow?

p-himik 2024-06-10T20:07:32.940889Z

An fx event handler accepts coeffects and returns effects. If you always pass :db around and don't rely on other coeffects, the effects map can play the role of the coeffects map. So you can chain any fx handler functions together. There's a relevant discussion logged here: https://gist.github.com/bowbahdoe/7fd8714cd910d43eb3229f967d95cbc6 And a write-up here: https://gist.github.com/olivergeorge/edc572eab653cc228ec5ecbbcc8271a2

fabrao 2024-07-14T17:27:43.817799Z

@rende11 why don't you use https://github.com/day8/re-frame-async-flow-fx ? You can control every steps.

p-himik 2024-07-14T17:31:34.663139Z

There's been plenty of discussions of downsides of using that library here, especially when done for anything other than app startup.