Fork me on GitHub
#re-frame
<
2020-08-10
>
Oliver George03:08:38

Idle thought of the day. I think re-frame handlers would be more composable if they returned two keys :db and :fx where :fx is a collection.

Oliver George03:08:40

:db needs to be threaded through as each handler modifies the app-db in turn

Oliver George03:08:27

:fx would allow all side effects to be kept in a list and executed in turn. No chance of clobbering each other.

Oliver George03:08:51

e.g {:fx [{:dispatch ...}{:dispatch ...}{:dispatch ...}{:dispatch ...}]

Oliver George03:08:04

So to compose you thread :db through handlers and collect up all :fxs returned.

Oliver George03:08:23

Expecting answers such as: been there done that, you're a monster, shouldn't you use more interceptors...

mikethompson04:08:39

@olivergeorge It is a good idle thought. I have made this comment elsewhere: if I had my time over again, I would absolutely make effects be a seq, rather than a map

mikethompson04:08:39

Upside: 1. It gives ordering (not that useful, but an interesting property) 2. no need for dispatch-n as you point out (this same -n issues comes up a lot with other effects like http GETs etc Downside: 1. slightly nosier visually with the additional structural nesting. 2. breaking change

mikethompson04:08:18

So I'm interested in your idea because it is a way to take away Downside 2, maybe.

mikethompson05:08:31

In terms of ordering, if I return both effects {:db ... :fx [....]} which effect is actioned first? :db ?

David Pham05:08:26

What if we put dB inside fx?

Oliver George06:08:47

I think :db is a special case. it's changing state... not triggering side effects. In fact, it's important to keep it out if you want to compose a bunch of simple handlers together which I think would be really nice and avoid a lot of typical boilerplate in handlers.

Oliver George06:08:32

There can be only one

Oliver George06:08:03

I guess there are cases where multiple fx would conflict (excepting :db) but none come to mind.

Oliver George06:08:24

I suspect it doesn't matter if :fx or :db is actioned first since they are independent... fx never have access to current app-db state.

Oliver George06:08:04

So long as all fx are triggered and the :db is updated before any other events are processed then it's fine. (In reflection, I'd do the :db first to allow for :fx which act on the app-db atom directly. Not something to encourage but logically what you'd expect - state has changed and after effects play out)

Oliver George06:08:41

I suspect the {:db ... :fx []} can be handled by re-frame v1 via an interceptor. Sounds fiddly but can't see why it wouldn't work.

Oliver George06:08:56

Could even be a new type of event handler registration which handles the return value differently: re-frame.core/reg-event-fsm (or whatever)

Oliver George06:08:04

(so non-breaking addition to reframe)

benny19:08:43

probable noob question, but why is it that when i dereference a subscription inline like so

(let [my-data @(re-frame/subscribe [:my-sub])]
  (fn [] 
    [:div my-data]))
the data doesn’t refresh but it does when dereferenced like so
(let [my-data (re-frame/subscribe [:my-sub])]
  (fn [] 
    [:div @my-data]))
even though the todo example uses the inline approach? (https://github.com/day8/re-frame/blob/master/examples/todomvc/src/todomvc/views.cljs#L55)

Oliver George23:08:03

Thanks @mikethompson I'll look forward to seeing what others think about it. I've done my best to clarify my thoughts in a comment.