Fork me on GitHub
#re-frame
<
2023-04-07
>
Stuart21:04:26

I have a question, I've tried reading the re-frame docs but I'm still a bit confused. I have this flow: 1. An event is dispatched. 2. This event is a reg-event-fx, it makes a call to an end point.

(rf/reg-event-fx
    :set-current-page
    (fn [{:keys [db]} [_ page]]
       {:db (-> db
            (assoc :current-page page)
            (assoc :loading? (if (= page :accounts) false true)))
    :http-xhrio
    (condp = page
      :investments investment-events/investments-api)}))
3. investment-events/investments-api makes a call to my end point. And I get the data, it looks like this:
(rf/reg-event-fx
 :process-investments
 (fn [{:keys [db]} [_ investments]]  
   {:db (-> db
            (assoc :loading? false)
            (assoc-in [:investments :grid] investments)
            (assoc :error nil))

   ;; I need another side-effect here to get and get the prices.   
 }))

(def investments-api
  {:method          :get
   :uri             (str lgc/base-and-port "/investment/")
   :format          (ajax/json-request-format)
   :response-format (ajax/json-response-format {:keywords? true})
   :on-success      [:process-investments]
   :on-failure      [:fail]})
Now, at this point, for each investment in investments, I want it to go and make another API call (to get current prices for each row). Then I want it to update the app-db once they are all finished. What should I be looking at here ? I feel it should be another reg-fx, but then how do I update a specific key in the app-db from a reg-fx, can I even do this, it would feel wrong. Is this a use case for co-effects ?

Ben Lieberman22:04:23

Don't quote me as I'm fairly new to re-frame myself but I think you can have a :dispatch key in your map that dispatches other events

Ben Lieberman22:04:55

That's in the docs somewhere I'd have to find it

Ben Lieberman22:04:10

Like this I think

Stuart22:04:06

Thanks, I'm still a bit confused how I actually get the results form the api calls into the maps in my app-db. At some point I think I have to end up with a reg-fx. I dont think I should actually be doing the api call in the reg-event-fx, but maybe I'm wrong.

Ben Lieberman22:04:17

That's the point of http-fx if I understand it though. I use it the same way you do but I haven't gotten to the point where I'm doing the side effects as a result. Maybe an interceptor could be used here?

p-himik03:04:58

So you have an event that must get some data asynchronously with N items, get more data asynchronously for each of those items, and then dispatch another event on completion. You can register a new effect (with reg-fx) for that, but it's not needed if you do such a thing only once. You can instead: 1. Make the initial event use :http-xhrio (or any other similar effect), just as it currently does 2. In the success handler of that effect use an event (`:process-investments` in your case) that will dispatch new N events, one for each retrieved data point. The currently preferred way is via the built-in :fx effect but can also be done via an older :dispatch-n effect. That event will also save any necessary intermediate data to the DB along with the count of the things it should be receiving 3. Those N events have all the same ID and handler, they just receive different argument. And that handler again uses :http-xhrio 4. That effect from the above receives yet another success event where its handler stores the received data somewhere and decrements the count from the previous point. If the new count is 0, that handler dispatches a completion event How exactly you implement that counter is up to you - you can avoid an explicit counter and go by the amount of the initial data and amount of the newly received data. But the things you must absolutely do are: tracking the current state correctly and handling all the errors. It might easily be that one of those N requests fails, and your app should fail gracefully there instead of displaying a perpetual progress bar.

p-himik03:04:56

To slightly help with that, you could use https://github.com/ingesolvoll/re-chain or something like that.

p-himik03:04:45

But I would recommend implementing it all in plain re-frame first just to wrap your head around the approach.

p-himik03:04:34

Oh, forgot to mention the most important thing - if the API you're querying is in your control, then you should really coalesce all those requests into one to avoid the N+1 problem to the most possible extent.

2
😀 2
Stuart12:04:47

Thank you so much! That was exactly the sort of guidance I was looking for. It makes sense. Brilliant, thank you.

Stuart13:04:47

Oh of course, you are right, I can basically do this in my backend. I get some data from the db, then for each I can make the relevant API call and just return the complete information to the front end. That is probably a lot simpler.

Stuart13:04:09

BUt it's a learning project, so I'll probably do as you explained just to learn how to do it.

👍 2