Fork me on GitHub
#re-frame
<
2019-02-12
>
andrea.crotti12:02:05

so in the todomvc example in the reframe project I see this way of defining an interceptor

(defn check-and-throw
  "Throws an exception if `db` doesn't match the Spec `a-spec`."
  [a-spec db]
  (when-not (s/valid? a-spec db)
    (throw (ex-info (str "spec check failed: " (s/explain-str a-spec db)) {}))))

;; now we create an interceptor using `after`
(def check-spec-interceptor (after (partial check-and-throw :todomvc.db/db)))

andrea.crotti12:02:20

but if I do something similar re-frame complains that I'm using an old style

andrea.crotti12:02:34

should we just update the example?

andrea.crotti12:02:16

I'm surprised that the actual example which seem outdated is actually much newer than interceptors.md though from git blame

ag18:02:28

So here’s kind of a controversial thread I’d like to start. Very often I see people willy-nilly cherry pick things off of state db - in events, and even in subs (where clearly using signal i.e. :<- [:foo] is better). So I’m trying to make it a strict rule in my team: - always use an event to write something to db - always use subscriptions to read from db (don’t simply use get and get-in when you need a value) The first rule kind of is already accepted as a normal practice, but the second one gets abused all the time, because there’s no easy or idiomatic way to re-use subscription in an event. And it’s so natural to simply do get-in db [:something :something]. And it gets really messy when you’re dealing with complex nested structures. One might argue that sometimes though you really need to read from db in an event body. For those rare cases you can inject-sub https://github.com/Day8/re-frame/blob/master/docs/FAQs/UseASubscriptionInAnEventHandler.md But that a) looks like a hack b) harder than simply using get-in I’m having hard time to convince my teammates, what do you guys think? am I right?

minikomi08:02:47

sorry for the question -- what is :<- ?

manutter5118:02:22

I think event handlers are a special case, precisely because there’s no easy way to grab a subscription value from inside an event handler. For that sort of thing, get-in seems like a reasonable and efficient approach (as long as you don’t need to get a subscription value from a layer 3 sub).

manutter5118:02:32

So I’d say “use subscriptions everywhere BUT event handlers; use get-in inside event handlers if you can, and use inject-sub if you need a calculated subscription value.”

manutter5118:02:46

That said, I kinda wish there was some mechanism you could use to easily “peek” at the current value of a sub, for use in event handlers.

manutter5118:02:34

The subscription values are currently cached someplace, seems like it should be possible.

ag18:02:04

> For that sort of thing, get-in seems like a reasonable and efficient approach exactly because it seems to be so much simpler and it’s idiomatic Clojure. This is what I see very often - there are bunch of events in which things simply read the keys off of db to feed those to :http-xhrio. This makes difficult when you change the events that write those keys to db in the first place. If you have no other mechanism to read from db but only subs - this forces you to think differently, instead of having to track what keyword vectors contain what data in your head you think in terms of what subs are responsible to pull the data and because subs are nicely composable it simplifies things a lot

manutter5118:02:19

Yeah, get-in only works well when the structure of app-db is relatively stable and unlikely to have drastic changes. If it’s not — well, you can always make a map of subscription names to get-in vectors, so that if the structure changes you only need to edit one place.

ag18:02:17

What I’m trying to say though - instead of thinking in terms “this key vector contains this data in db”, think “this sub (with its signal graph) gets me the data I need”.

ag18:02:53

It does make things a lot much simpler to reason about when you know that the only way to read from db is to use a subscription

ag18:02:37

“I don’t care where the data is stored in db, simply use this sub and get me what I need”

manutter5119:02:27

Yeah, the pain point is not being able to just subscribe to subscriptions from inside event handlers.

manutter5119:02:54

A map would just be a pseudo-subscription, as a workaround.

ag19:02:13

And you don’t need that in most cases. You can pass the data that event needs via dispatch

ag19:02:08

and because using get-in is easy, things often get hairy. Why would one pass things via dispatch if it’s simply can be read using get-in in the event body? That blows up the event unnecessarily and now you have bunch of [:foo :zap :zop] vectors sprinkled in various places in your codebase

ag19:02:34

I wish the docs emphasized it somewhere: Always try to use subscriptions to read from db.

manutter5119:02:53

There is the “A Final FAQ” section at the end of the Subscriptions Cleanup page https://github.com/Day8/re-frame/blob/master/docs/SubscriptionsCleanup.md

ag19:02:05

I’ve seen this, It doesn’t say anything about cherry picking things off of db in the events though

mikerod19:02:14

@ag I’ve avoided passing large objects in on dispatch

mikerod19:02:38

one reason, it’s makes it harder to see the “audit trail”, like via logging

mikerod19:02:56

so that’s been a downside where I ended up relying more on accessing db values from within the handler

mikerod19:02:12

I tend to only dispatch like “id”’s of what I’m looking for, not the thing itself

mikerod19:02:34

to keep the dispatch itself printable/readable - some tooling automatically shows dispatch calls

mikerod19:02:10

I am not always a fan of how the event handlers have to do get-in to find things, while subs abstract that away though. Something like @manutter51 said about grouping paths with subs name has occurred to me as well before - have to ensure it isn’t a derived value coming out of the subs though for that to work. I don’t like using subs as cofx really just due to the pitfalls that can happen there, like a subs only used in an event handler has to be cleaned immediately etc

mikerod19:02:02

also a subs with a more complex signal graph isn’t easily representable as a path in the db, it could be multiple paths and can’t rely on it not using computed values. I’ve recently been adding more derived values into the db via the event handler instead of deriving as heavily on the subs side

mikerod19:02:44

that way the event handlers can access this derived info directly via paths. I’m not sure this is great, but it works for the most part. you can use interceptors to be “reactive” on this side of things so that derived db values automatically update

lilactown19:02:01

would it make sense to have normal functions that operate on the app-db that would be used for both accessing db in events and subs?

mikerod19:02:30

such as re-frame.core enrich, after, on-changes, or something custom

mikerod19:02:49

@lilactown the problem is the signal graph I think

mikerod19:02:54

in a subs, you may have it layered

mikerod19:02:22

so the sub behavior you wish to recreate is a fn at the end of a 3-part chain of subs

mikerod19:02:28

your event handler will just have the whole db

mikerod19:02:30

so the fn isn’t the same

mikerod19:02:43

also, you are re-deriving the information on the event side

mikerod19:02:55

could already have been computed - this may not matter to you if fast enough or whatever

mikerod19:02:02

you could be sure to do all computed values for subs in reusable fn’s though and compose them together sort of the same way again on the event handling side. doable, but still could lead to dual maintenance I think

lilactown19:02:26

yeah I've never been bottlenecked by deriving from the app-db

lilactown19:02:34

might be able to just use normal memoization in that case

lilactown19:02:21

I didn't think about how subs can be layered. I generally don't do that

5
kaosko19:02:58

anybody using re-com here? I was just wondering if there's some clever add-on to handle "enter submits an ajax form", i.e. a generic way to handle on-key-press for (re-com) input fields. not a big deal, but figured somebody else must have gotten frustrated with it