Fork me on GitHub
#re-frame
<
2019-05-05
>
hoopes02:05:46

is there a better pattern for it? just looking for the best/most obvious way to react after 2 or more async things happen. like, i dispatch-n a couple ajax calls, and want to do something when they’re done.

lilactown03:05:09

it sounds like the issue is that (assuming your using the relatively standard one) the ajax effect handler has a 1:1 to event and ajax effect

mikethompson03:05:31

Managing two async events (either of which might fail or timeout) makes the state machine more complicated.

lilactown03:05:08

I would consider writing an effect handler that would fire the 2 ajax as one effect

lilactown03:05:56

defining the state transitions locally in the event/effect makes more sense to me than spreading it over multiple events/effects

mikethompson03:05:56

The firing of the events is the easy bit :-)

lilactown03:05:09

but I haven’t tried it 😄

mikethompson03:05:22

dispatch-n easily fires two events

mikethompson04:05:03

The challenge is in subsequently managing the consequential state machine

mikethompson04:05:44

That's kinda why we wrote async flow

mikethompson04:05:05

But it feels like overkill for such a simple case

lilactown04:05:47

probably the 80% case could be solved by an effect like: {:http-n {:requests [{...}] :on-all-success [::success-result] :on-failure [::failure-result]}

hoopes16:05:39

today, i hold some sort of "in flight" id in the app db, and set that as an arg in my on-success handlers, so they know what "group" of events they belong to. it's a decent amount of bookkeeping. the chaining of promises, while not really simpatico with the "dispatched events" style, has some advantages. in any case, i'll try to think harder about it, and see if anything shakes out. thanks for responding!

James Vickers21:05:06

Beginner question on the 'right' way to do something. I am making a loan calculator, so it has values like interest, term, price, down-payment, principal, monthly-payment. Changing some of these values changes more than one of the others, for example changing price should change principal and monthly-payment, same for changing down-payment. How do people manage events that cause other data to change also? I can do it in a verbose way just by recomputing all the other values that need to change in each particular event handler. Is there a more concise and idiomatic way to mange it? Fire other event(s) from an event handler? I'm thinking of Excel-style flow where I define the 'formula' for the data in terms of each other, not sure if that's reasonable here.

lilactown21:05:32

I would try and separate your values into ones that are independent and ones that are dependent

lilactown21:05:12

the independent ones can live in your state, and the dependent ones can be computed based on the state

James Vickers21:05:53

I think some of the dependent ones such as monthly-payment will be used downstream to e.g. plot a graph of the balance over time

James Vickers21:05:14

I was thinking of writing some helper function that computes the ~5 values together as a map when any of them change, and calling that from each of the event handlers for the 'independent' values. Just didn't know if there was some idiomatic way of handling that with more events or something

lilactown21:05:31

I would create subscriptions for each of them

lilactown22:05:04

unless I’m misunderstanding you

lilactown22:05:39

values that depend on state shouldn’t be computed in event handlers. instead, they should be computed in subscriptions

lilactown22:05:38

so you might a subscription called :loan/monthly-payment that is computed via values from the app-db, and then your calculator and graph views can both subscribe to it via (rf/subscribe [:loan/monthly-payment])

James Vickers22:05:13

I think that would work well for that one, thanks!

James Vickers22:05:13

Not sure how to handle values that can either change from user input for because another upstream value changed. An example is amount-down (the down payment in dollars), which can change either from user input or because percent-down (the % down payment) changes.

lilactown22:05:51

in your handler for the user changing their percent down, you can calculate the amount-down based on the price and commit that to the app-db

lilactown22:05:43

basically, you want to try and maintain one source of truth for each “fact”. if you have multiple entries in the app-db tracking the same things, you end up having complicated coordination where multiple values need to be changed simultaneously, always

James Vickers22:05:27

Ok this is making more sense :thumbsup: so the values at the bottom of the event graph basically that don't change other values, make subs for those

James Vickers22:05:26

I guess one that might still be verbose is changing price? That event handler would have to change price, percent-down. That's not too bad though.

lilactown22:05:50

yeah this goes back to percent-down being a computed value

lilactown22:05:02

you could have an :loan/update-percent-down event which computes the amount-down and commits that to the app-db. and then a :loan/percent-down subscription which computes the percentage down based on price and amount-down

lilactown22:05:43

this way you only keep track of the “Amount a person must pay down” in one place in the DB.

lilactown22:05:10

you could obviously flip this the other way and track percent-down in the app-db and have amount-down be calculated

James Vickers22:05:51

Don't I need to track both of them in the db since both can be changed by the user?

James Vickers22:05:13

Or are you saying like don't track one of them to simplify

lilactown22:05:31

you only want to track the same Thing once in the DB

lilactown22:05:47

if two keys are always changed in sync, you are probably tracking it multiple times

James Vickers22:05:29

Make sense, percent-down is basically a 'view'

James Vickers22:05:41

amount-down is the main piece of data

lilactown22:05:23

yep. E.g. when someone updates the percent down:

(reg-event :loan/update-percent-down
  (fn [cofx [_ new-percent]]
    (let [price (get-in cofx [:db :loan :price]
          new-amount (* price new-percent)]
      {:db (assoc-in (:db cofx) [:loan :amount-down] new-amount)})))

lilactown22:05:36

(reg-sub :loan/percent-down
  (fn [db _]
    (/ (get-in db [:loan :amount-down]) (get-in db [:loan :price]))))

lilactown22:05:58

might be typos. coding in slack is hard 😛

James Vickers22:05:29

Thanks, this is very helpful!

James Vickers22:05:56

Is there a reason for using reg-event :loan/update-percent-down (I think it's actually reg-event-fx right) instead of reg-event-db ?

lilactown22:05:40

oops yeah, should be reg-event-fx 😄 and in this case, not really

lilactown22:05:56

reg-event-db is shorthand. it can be used for events that only change the db value

James Vickers22:05:12

Cool I think that's all that would be doing right?

lilactown22:05:44

if you want to do other effects (like a network request, update localstorage, change the URL bar, etc.) then reg-event-fx is the general way to do things like that

lilactown22:05:52

yep, in the code I wrote above that’s all I’m doing