Fork me on GitHub
#re-frame
<
2018-01-10
>
kenny00:01:39

Why is the re-frame db not passed to the extractor fn of a subscription defined with an extractor fn and a computation fn?

mikethompson01:01:35

@kenny I'm assuming you mean signal fn instead of extractor fn. If so, to answer your question: (1) it generally isn't needed (2) if it is then do this:

(reg-sub 
    :db 
   (fn [db]  db))
which would allow you to then use (subscribe [:db]) within the signal fn of whatever further subscription needs to get to all of db AND, presumably, something else. But you'd need to be doing something, er, exotic to need it.

kenny01:01:20

@mikethompson No I meant extractor fn. If I have a subscription defined like this:

(rf/reg-sub
  :my-sub
  (fn [arg1 arg2]
    (println (pr-str arg1 arg2))
    "abc")
  (fn [s]
    (str s "d")))
arg1 is the query-vec [:my-sub] and arg2 is nil.

mikethompson01:01:07

(fn [arg1 arg2] ...) is known as the signal function

kenny01:01:41

Ah I could've sworn I was just reading the docs and it said otherwise 🙃

kenny01:01:08

It says "extractors", which confused me I guess.

mikethompson01:01:10

I just did a hasty search and couldn't find that reference

mikethompson01:01:19

Ahh, non written

mikethompson01:01:28

I'll correct, sorry

mikethompson01:01:38

But my comments above stand

kenny01:01:57

Right. Still pondering my use-case.

mikethompson01:01:59

You generally have multiple layer 2 subscriptions. They are made trivial.

mikethompson01:01:08

They just "extract"

mikethompson01:01:21

Then further computation is done in layer 3

mikethompson01:01:39

The Layer 2's just want access to db. Nothing else

mikethompson01:01:01

The Layer 3's will take layer 2s as input (one or more)

mikethompson01:01:18

Layer 3 DO NOT want direct access to db

mikethompson01:01:31

Because they don't want to re-run each time app-db changes

mikethompson01:01:11

The purpose of this arrangement is efficiency.

kenny01:01:19

My use-case is a bit, in your words, exotic. Example:

(rf/reg-sub
  ::example
  (fn [db _]
    (do-query my-query (:selected db)))
  (fn [query-result]
    (sort query-result)))
do-query returns an ratom which I'd like to use as the input to the computation.

mikethompson01:01:00

do-query queries a remove database?

kenny01:01:17

You mean remote?

kenny01:01:35

Specifically it is integrating Posh queries with re-frame with a join across both DBs.

kenny01:01:27

Yes, I have looked at existing libs that do this and they are not solving the same problem.

kenny01:01:37

I believe this would work:

(rf/reg-sub
  ::selected
  (fn [db _]
    (:selected db)))

(rf/reg-sub-raw
  ::example2
  (fn [db _]
    (ratom/reaction @(do-query my-query (:db @db) @(rf/subscribe [::selected])))))

(rf/reg-sub
  ::example2-sorted
  :<- [::example2]
  (fn [query-result]
    (sort query-result)))

danielcompton02:01:09

I don't think I'm fully following the signal graph, but you can use the rarely seen double-deref @@ to possibly simplify some code here

kenny02:01:52

Not sure I follow.

danielcompton02:01:30

Just wondering if you can remove ::example-2 and @@ on do-query

danielcompton02:01:45

Unless you want it to be a separate subscription to use elsewhere

kenny02:01:18

Does @@ do something special that is not just (deref (deref))?

danielcompton02:01:23

no, same thing

kenny02:01:55

I think that'd throw an exception. do-query simply returns a ratom.

kenny02:01:50

I think what I'm after is a function that allows you to create all of your input signals given the DB and still attach a computation.

danielcompton02:01:08

kinda like half-way between reg-sub-raw and reg-sub?

kenny02:01:37

Trying to think about what that'd even look like.

kenny02:01:33

Something like this?

(reg-inputs-sub
  :<- [::selected]
  (fn [db [selected] query-v]
    (do-query my-query (:db db) selected))
  (fn [query-result]
    (sort query-result)))

danielcompton02:01:36

oh, a three level thing

danielcompton02:01:29

You could have do-query just return the reaction in one sub, and then you deref it in the next

kenny02:01:54

I don't think there is a way to accomplish the same thing as the above.

danielcompton02:01:07

(rf/reg-sub
  ::selected
  (fn [db _]
    (:selected db)))

(rf/reg-sub
  ::db
  (fn [db _]
    (:db db)))

(rf/reg-sub
  ::example2
  :<- [::selected]
  :<- [::db]
  (fn [[selected db] _]
    (do-query my-query db selected)))

(rf/reg-sub
  ::example2-sorted
  :<- [::example2]
  (fn [query-result]
    (sort @query-result)))

danielcompton02:01:34

does that work?

kenny02:01:57

Right but that's not efficient. ::example2 will get called every time the DB changes.

kenny02:01:19

Oh sorry, I see.

kenny02:01:03

Yes that would work.

kenny02:01:57

Is there a reason re-frame forces the creation of ::example2 and ::example2-sorted? If I only ever care about the latter, why should I need to create two subscriptions for it?

kenny02:01:25

It seems cleaner to be able to attach the computation fn to ::example2.

kenny02:01:57

Wait a minute, I don't think your example will work. do-query returns a ratom, not a value.

mikethompson02:01:28

But note the reservations towards the bottom

mikethompson02:01:19

"The Alternative Approach"

mikethompson02:01:40

and "Absolutely Never Do This"

danielcompton02:01:54

I think it will still work, because computation-fn is still run inside a make-reaction

danielcompton02:01:57

The reg-sub function does the dereffing of subscriptions for you so you don't need to think about it, but derefing a subscriptions (reactive) value is also going to happen inside the same reaction context, so should be fine too

kenny02:01:06

I think that link is mostly geared around actually external data. What I'm suggesting is being able to functionally create the input signals to a subscription. Hmm, I'll try it. My understanding was that the computation-fn needed to return a value, not a ratom.

danielcompton02:01:07

It does if you want to be able to use it in other reg-subs without having to deref it, but it's just a convention to avoid mistakes

danielcompton02:01:26

(make-reaction
  (fn []
    (computation-fn (deref-input-signals subscriptions query-id) query-vec)))

danielcompton02:01:00

If you computation fn returns a value then it will be wrapped in a reaction which everything else expects

danielcompton02:01:25

by convention you'd want everything to be taking and returning values for simplicity

danielcompton02:01:00

but if you do your bookkeeping carefully and are aware that you're returning a reaction that returns a reaction, then you can do what I showed above

kenny02:01:27

So that works without throwing an exception except that ::example2 does not get updated when the do-query ratom changes.

kenny02:01:17

Deref'ing @(do-query) does not work either.

kenny02:01:34

Shit, in devcards. Lemme try out of that.

kenny02:01:00

Ignore what I just said, works as expected.

danielcompton02:01:29

Great! gtg, can discuss more tomorrow your time

kenny02:01:09

About time for dinner anyway 🙂 ttyl

spacepluk13:01:57

hi there, is anybody using reagent-material-ui?

mikerod18:01:02

Did you have a specific question about it? I’ve heard of it being used a few times before.

mikerod18:01:23

I’ve been using react-bootstrap so far, but it isn’t a significant difference

mikerod18:01:13

Also, there is https://github.com/gadfly361/soda-ash which is a cljs wrapper layer that may or may not be something valuable to you in using it

vikeri16:01:55

Just double checking, if I run (do (dispatch [:a]) (dispatch [:b])) Then :a will always complete before :b is processed?

mikerod18:01:53

This comment says it is added to a FIFO queue

mikerod18:01:25

I believe that is what I referenced to give myself confidence that that is a valid assumption

mikerod18:01:36

In contrast, you cannot assume the order of when effects happen

mikethompson21:01:31

@cmal Slightly late to this, but we have used vega which is a layer over D3 for charting. It is has gone well for us. Depends what charting you want to do. A bit of a learning curve for vega, mind you there's a pretty decent learning curve with D3 itself, too. Vega-Lite is easier.

raymcdermott23:01:09

using re-frame-test and karma and it all works great locally … wondering if it runs headless?

raymcdermott23:01:07

hmmm, ok I see that karma has a phantom.js launcher … still wondering if that work for re-frame

raymcdermott23:01:43

[ I plan to use the re-frame-test for events /subs testing and I etoian for the web driver aspects so it would be nice to be able to use the same browser ]