Fork me on GitHub
#re-frame
<
2017-09-07
>
qle-guen09:09:24

hey, I'm writing an effect for a http POST request with cljs-http, I'm doing (take! (http/post url...) on-success)), on-success being aome assoc function on the db, but the db gets modified in a strange way, it prints as: #<Reaction 2: nil>

qle-guen09:09:47

btw, there's no existing effect for http requests?

danielneal10:09:21

There is a re-frame-http-fx library

danielneal10:09:04

would recommend

qle-guen11:09:12

@danieleneal yeah I may use that but I'd like to understand what I'm doing wrong anyway

danielneal11:09:27

can you paste your exact handler code

qle-guen11:09:49

you mean the effect?

danielneal11:09:57

and the handler

danielneal11:09:55

ah ok I think I can see what the problem is

danielneal11:09:00

This db parameter is a value

danielneal11:09:34

when your on success function runs, you are associng into a value but the db itself doesn't change

danielneal11:09:47

to make the db change you need to provide the :db effect in a handler

danielneal11:09:34

the best way to write the effects is to pass in another event to dispatch, rather than a callback

qle-guen11:09:46

something like (dispatch {:db [new-db]}?

danielneal11:09:03

I'll put an example together

danielneal11:09:06

brackets probably wrong but that's the idea

danielneal11:09:15

so you then have access to the db again in the new handler

qle-guen11:09:35

hmm yeah I see, I'll try

qle-guen12:09:45

No, I still got the same result. First #<Reaction 2: nil> on the first time the component gets loaded and after #<Reaction 5:nil> once the db gets updated

qle-guen12:09:20

it seems to me that my use of channels is wrong

danielneal12:09:30

you mean your db is being replaced by #<Reaction 2: nil> ?

qle-guen12:09:01

when I subscribe to :token and print it, it prints that

danielneal12:09:29

sounds like token is nil and you're not dereferencing the subscription

danielneal12:09:53

I'd put a println in the reg-event-db to check the response

qle-guen12:09:59

oh yeah, that's one thing

qle-guen12:09:26

the value is fine in reg-event-db :auth/ok

danielneal12:09:25

put up your new code including the subscription?

danielneal12:09:17

you say the value is fine in reg-event-db :auth/ok?

qle-guen12:09:11

maybe the component doesn't get updated

qle-guen12:09:37

I think that's the problem

danielneal12:09:19

yeah that all looks right to me

danielneal12:09:51

but the component should update automatically if you're dereferencing a subscription

danielneal12:09:14

I'm especially not sure why (prn @token) is returning a reaction

qle-guen12:09:02

ok got it \o/

qle-guen12:09:13

it's just me being stupid, as always

qle-guen12:09:36

the path is the response wasn't right, it was nested in :body

qle-guen12:09:43

sorry for wasting your time

danielneal12:09:51

glad I could help

stvnmllr213:09:14

Is there a standard effect handler to dispatch something later in time? With setTimout I'm guessing.

stvnmllr213:09:36

Like showing something on page for a few seconds

danielneal13:09:26

yep, :dispatch-later 😄

stvnmllr213:09:02

genius! thanks. not sure how i missed it

qle-guen13:09:59

Hey I need to write an effect that depends on another async effect. The result of that effect is nil when I access it in reg-event-fx's db parameter (because async)

qle-guen13:09:55

I could conditionally dispatch the new effect in my component: (when (not-nil @result) (dispatch ...)) but it doesn't seem right

danielneal13:09:58

rather than in the component, you can initiate the new effect in the handler of the previous event

danielneal14:09:02

(reg-event-fx
    :some-async-event-received
     (fn [{:keys [db]} [_ resp]]
     {:db ...
      :some-async-fx (if (nil? (get-in resp [:body :result]) {:post :this ...} {:post :that ...}

qle-guen14:09:17

I imagine I could do that with an interceptor to register that in the cofx argument right?

danielneal14:09:56

um, if the example is similar to the one before you can just do that you don't need any additional interceptors

danielneal14:09:36

(reg-event-fx :auth/ok (fn [{:keys [db]} [_ resp]] {:db ... :POST (if (nil? (get-in resp [:body :result]) {:url ...} {:url ...}```

qle-guen14:09:30

Ok no, it can't work that way, because I will use a bunch of :GET effects that all need the token obtained from my initial :POST request

qle-guen14:09:17

so again I could just render my main component only if the token has been obtained, but it seems that re-frame would allow me to make it more reactive than that

kasuko14:09:25

What stops you from storing that token in the DB in the :POST success handler for retrieving in the :GET handlers

qle-guen14:09:07

that's what I'm doing basically, but the whole thing being async, I just get nil when I take the token in the db

kasuko14:09:14

I think having a subscription that determines if the main component is rendered only if that token is present in the db is very re-frame like

qle-guen14:09:39

ok I'll just do that then

kasuko14:09:55

If you have a lot of “setup” that needs to be done, and you have several states a long the way you might want to model it as a state machine.

vinai15:09:54

I've got a list of articles in my app-db for rendering. Now I need to make them deep-linkable, so I would like to build a vector of bidi routes out of the articles. This isn't the job of a react component though, so I was wondering what the common good practice is for somthing that involves data from the app-db, but isn't part of the rendering. Do I keep a copy in a separate atom for the sake of creating the routes? Should I access the app-db atom directly? Is there another, cleaner way?

kasuko15:09:49

@vinai I’m no expert but first, I don’t think re-frame is about just rendering. That’s reagent and part of the reason re-frame is great is because it moves beyond just the view. For me the app-db is just that, the db for the entire app. Is routing part of your app? So with that said, let me ask, what do you lose by storing the routes in the app-db?

vinai15:09:25

@kasuko Thanks for the input. I guess I loose nothing, except duplication, as the routes are a function of the article data.

danielneal15:09:34

You could have the routes as a subscription or rather just a function of the db

kasuko15:09:44

Would you be able to make the routes a subscription based on the app-db? You’d probably have to add some manual reactions to update the routes

kasuko15:09:54

hehe, too late

vinai15:09:57

That sounds attractive.

kasuko15:09:53

Ultimately this sounds like something that fits into the “flow” of re-frame very nicely but instead of the output being DOM on a screen it’s routes in memory

vinai15:09:48

So I could have a subscription, that returns the routes?

vinai15:09:36

Trying to wrap my head around that. So far I saw subscription kind of like a stream, and the routing table like, well, a static table that gets updated sometimes.

danielneal15:09:52

The subscriptions are cached

danielneal15:09:04

and they'll only be recalculated when the things that they depend on changed

vinai15:09:04

I don't think I can pass anything but a handler to bidi. I need a vector of vectors for that. My gut feeling is an event fx that updates the routes table would be a better fit.

vinai15:09:48

Or I indeed just drop that table (or the articles part of it) into the db and then I could subscribe to it.

vinai15:09:44

The routes are passed to bidi/path-for and bidi/match-route functions.

danielneal15:09:49

Yeah I'd definitely keep it in the db if it's data that changes

kasuko15:09:05

Wouldn’t that work

vinai15:09:41

wow. cool

vinai15:09:08

yeah, I guess it would

vinai15:09:32

This bit: @(re-frame/subscribe [:routes]) that is the missing puzzle bit for me

vinai15:09:55

deref on a subscription to get the current value

kasuko15:09:08

It’s basically like turning the match-route function into a form-1 view component

kasuko15:09:46

and this way if your articles in the db ever change you have to do absolutely nothing to have the new routes generated

vinai15:09:25

Thanks, that was helpful! 👍

kasuko15:09:39

Though I would probably change the :routes subscription from a Layer 2 to a Layer 3 subscription. I changed the snippet above to reflect that

kasuko15:09:05

That way the expensive route recalculation only occurs when the articles change, not anything in the app-db

vinai15:09:57

That's what I started writing, too, as I have a articles subscription already!

vinai16:09:28

You probably knew, but the subscription on the routes works great.

kasuko16:09:37

I didn’t know. I was pretty certain but it’s great to hear it did work!