Fork me on GitHub
#re-frame
<
2021-07-14
>
zackteo04:07:10

Hello, I was looking at https://github.com/day8/re-frame-http-fx#optional-handler-for-on-request and realised that keyword examples are ::http-post is it a standard to have :: for events in re-frame?

mikethompson04:07:49

If you are in namespace blah then ::kw is shorthand for :blah/kw

zackteo04:07:16

right, okay I am starting to remember this 😅

mikethompson04:07:23

So it is a bit of syntactic sugar from Clojure

mikethompson04:07:00

And, yes, re-frame keywords for events, subscriptions etc, are often namespaced

lsenjov04:07:57

It’s good practice so you don’t accidentally collide with events in other namespaces

lsenjov04:07:45

Also if you have [foo.bar :as bar] in your require, then ::bar/baz will expand to :foo.bar/baz

dpsutton05:07:02

you can just evaluate those keywords in the repl. it'll expand to the full de-sugared form

Oliver George06:07:47

Has there been any discussion to allowing :fx handlers to take many args? Seems like an easy thing to accommodate... https://gist.github.com/olivergeorge/a149956af8d137372a954603da15d3e2

p-himik08:07:31

It would then work differently from using effects as is, no? {:effect [1 2]} will call its handler with a single argument [1 2]. I think it's reasonable to expect that {:fx [[:effect [1 2]]]} will do the same.

mikethompson09:07:31

@U055DUUFS what @U2FRKM4TW says ... plus it feels your suggestion feels like it is trying to take me back to "positional args" for functions which is something I've been learning alowly not to do ... don't drag me back down that path - it has taken me long enough to learn not to :-)

Oliver George09:07:58

fair call. i think we're all better off with the slightly more verbose arg map.

Oliver George09:07:48

simple vs easy and all that

zackteo08:07:28

How should I approach dispatching multiple events in re-frame? Say for example I want to dispatch an event to query the database and an event to change a page when clicking a button? I understand they can be on the same event as :db and :http-chrio <- should this be the approach that I should take?

zackteo08:07:35

Especially because I have a {:change-page] event that I want to use instead

mikethompson08:07:14

I wouldn't be sending an event to change the page. In general one event handler should be "calling" over event handlers. And event models something that the user does (or an external agent). The "handler" for that event should itself implement the necessary effects (including page changes) and not "send further events". So, in my opinion, you'll want your event handler to change the state in db, to indicate the change in page, and then have the UI reactively update (because the UI is just a rendering of state).

p-himik09:07:58

> I wouldn't be sending an event to change the page. > In general one event handler should be "calling" over event handlers. What about being able to reuse already set interceptors on some event? Reusing just the handler won't reuse them, whereas :dispatch will. Perhaps we had this discussion before, but I can't recall...

mikethompson09:07:11

Yeah, I'm definitely a believer that the common code (for changing pages?) should be factored out into a function and not an event handler (with convenient interceptors). Then the event handler can be implemented as a composition of functions - one of which looks after changing pages.

mikethompson09:07:40

I wish i had more time to put together some docs on this, justifying what I'm asserting (without much evidence). But ... no time currently. Complicated life.

p-himik09:07:19

Maybe such docs would convert me as well. :) So far, reusing events is just way too comfortable given interceptors reuse along with an automatic and more granular instrumentation with re-frame-10x. But also, I will probably notice issues in such an approach myself if I ever stumble upon them in my workflow.

mikethompson09:07:15

Do you ever get a bit lost in what sends what to whom?

2
mikethompson09:07:26

Ie. the control flow is confusing?

p-himik09:07:56

Not really, for two reasons: • Events that are reused are rarely dispatched in batches by multiple different events, so just linear event tracing in re-frame-10x already gives an almost perfectly clear picture • I'm rather quick at understanding situations when the above is not the case - at least, enough to not notice it introducing any friction. There are patterns that often help me determine event chain immediately, and also each traced event has its fx map in re-frame-10x during development and in a logging service in production, so the worst case scenario is just clicking a few times, maybe entering an event name in the search panel Of course, having something like event originator would improve the situation a bit - but not nearly enough for me personally to even start thinking about how this could be implemented.

p-himik09:07:35

I remember being lost in control flow only in one particular kind of scenario - back when I was working for a company that wrote JS+Java enterprise software, it was JS spaghetti with a heavy use of anonymous callbacks mixed in with promises, without any sort of tracing.

emccue13:07:29

@U2FRKM4TW For context, all my rants have been the result of living in a codebase that had events that dispatched to other events

emccue13:07:44

idk what loc you've gotten up to, but for us it got to the point that re-frame-10x was almost useless with the number of "events" that triggered

emccue13:07:27

A very common one was having a "helper event" that set a loading flag in the db and sent off an http request

emccue13:07:53

go to a single page and the event log would have something like 10 http-request-with-loadingand a maybe 20+ set-specific-domain-model handling the results

emccue13:07:32

in addition to other "common" functionality

emccue13:07:15

and we • Lost stack traces - how did we get to this error? • Couldn't tell from a callsite whether it was a db event or one that could do a side effect • Had bugs because we weren't keeping good enough track of when state changes happened. Events being a queue and normal function calls being a stack meant that our expectations were often totally opposite reality • Basically couldn't unit-test simple stuff like "if we click this button, will the db be updated like so" or "if we click this button, will we send an http request" since it might be (and often was) deep within a "helper event"

emccue13:07:26

idk what benefit you are getting from interceptors - but for us it was mostly telemetry stuff. That fit in with just having a reusable fx

p-himik14:07:23

> Couldn't tell from a callsite whether it was a db event or one that could do a side effect Isn't it the case for your current approach as well? How do you make that distinction?

p-himik14:07:38

And how is that distinction useful?

emccue18:07:33

its the case at an initial dispatch site - an event can do both - but it was an issue when events were helpers to other events

emccue18:07:50

because some events just updated state and some just did effects and some did both

emccue19:07:50

we would have a situation where :A would transform the db db -> db' and :B would just do a side effect and :C would require db' to do db' -> db''

emccue19:07:48

:A would be named "set-thing" and B and C would be more generically named since they didn't just set - but the fact that they did set was an implicit dependency of other events

emccue19:07:04

like, lets say we moved A and B into their own helper event D

emccue19:07:13

it gets enqueued like this

emccue19:07:38

which pops to C, A, B

emccue19:07:45

now C gets db instead of db'

p-himik19:07:59

I see, makes sense, thanks!

emccue13:07:00

@U2FRKM4TW Another issue i'm reminding myself of working through a cruftier part of the code - Using logic to determine which events to dispatch is absolutely cursed

p-himik17:07:31

How is it different from determining which util function to call?

emccue18:07:05

untestable if, basically

emccue18:07:48

you have a condition there that will determine what to dispatch, but what the event is only loosely related to what is going to happen with the state or the side effects

👍 2
mikethompson08:07:31

Now, you might want to write a function to update the state for a page change. It might take db as an arg and it might produce a new db , maybe. And, in your event handler, you might want to call this function.

mikethompson08:07:56

But, IMO, you should not send a message to cause a page change.

mikethompson08:07:11

(from another event handler)