Fork me on GitHub
#re-frame
<
2018-11-06
>
Macroz09:11:38

What is your favorite way of handling Promise-like situations in ClojureScript / re-frame? I.e. chaining events and handlers like 1. set saving state, 2. save to server call, 3. when success reload from server. Do you use callback(-hell), re-chain, re-frame-async-flow-fx or aramis or what?

Macroz09:11:14

how does that work together with re-frame handlers?

mccraigmccraig09:11:51

it doesn't - it lets you compose promise operations, then you can spit out an event from the result. if you need the intermediate states in the app-db then one of the other approaches would be more appropriate

Macroz09:11:39

yeah I thought so, thanks for the idea though

Macroz09:11:35

generally I think I'm looking for a simple sequential chaining of handlers and the solutions that I found above were either not used much or more complex than I think they should be

Macroz09:11:53

so I'm wondering how people solve any slightly more complicated UIs

Macroz09:11:45

composing promises is definitely an answer but I don't see how that works out with re-frame well

mccraigmccraig10:11:48

it works out fine - promises are a nice abstraction and compose very well - you get a value or an error-state at the end which is straightforward to stick in an event

Macroz10:11:03

so your approach is, click button -> promise chain -> dispatch one re-frame event?

Macroz10:11:28

or do you rather use plain reagent?

mccraigmccraig10:11:19

yes, that's it

👍 4
mccraigmccraig10:11:06

we have some stuff which holds intermediate states in the app-db, which is currently a mess and will soon be re-frame-async-flow-fx, but that will only be in a couple of places in our 30kloc app

valtteri10:11:17

For relatively simple cases I pass “dispatch these if success” -vector to data-fetching events.

Macroz10:11:37

@valtteri thanks, I have done that as well, I count it in the callback category

valtteri10:11:09

Yep. For more complex chaining I’d also consider doing it on server-side if it’s not something purely UI-related.

mccraigmccraig10:11:57

ha, we use exactly the same promise-chaining model on the server-side - the code would be identical

Macroz10:11:28

the exact situation if I have in mind is a chain of saving current form data, uploading attachment, then reloading data

Macroz10:11:00

it doesn't make sense to add to API a separate endpoint for save form data and attachment unless you like building backends for frontends much

Macroz10:11:31

saving form data and uploading attachment are their own functions as well, only when the form has yet never been saved they need to be chained like this

Macroz10:11:46

not complex but this is the case when I started to wonder how other people do it

valtteri10:11:04

Do you need to deal with error handling? Should it rollback if any of the calls fail?

Macroz10:11:25

I can live with the failure not doing anything or partial update

Macroz10:11:43

so a simple chain is enough

mccraigmccraig10:11:11

for that exact case we don't save the form-data - we upload the attachment on the side, which returns an uploaded file descriptor, which gets used for a thumbnail presentation and as a path for a field in the form, whenever the form gets submitted

Macroz10:11:41

so you basically have free floating attachments that you garbage collect somehow separately?

Macroz10:11:04

this feature was first implemented so that the attachment must have the form and "application id"

mccraigmccraig10:11:59

free floating attachments that i will garbage-collect at some point in the future but not until storage becomes more than an insignificant cost 😬

Macroz10:11:13

yes that does simplify this case and it's a possible refactoring

valtteri10:11:19

Is it possible to send both form-data and attachment in one request?

valtteri10:11:23

Just started to wonder based on the convo. On a quick look js/FormData seems to support it https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects

Macroz10:11:15

yes it is! but it is a solution to this specific problem only and not to the genreal chaining needs

Macroz10:11:31

sometimes you don't e.g. control all the backends you talk to

Macroz10:11:43

or you need to BFF wrap all the backends etc. to control them

Macroz10:11:31

idempotent backends that coordinate multiple REST backends by rolling forward are cool but not the original question

valtteri10:11:45

Yep true that, sorry for off-topic but I was just generally curious. 🙂

Macroz10:11:24

no problem, it's all in this same problem space

Macroz10:11:34

pretty common requirement

Macroz10:11:21

often the answer is not to answer the original question but to rethink the whole case

valtteri10:11:43

Back to on-topic: I think stateful async chaining is quite complex by nature and that’s why general solutions are also complex. Using promises and firing event at the end sounds tempting.. But my gut tells me to avoid that for some reason.

mccraigmccraig10:11:20

you just need to add some monads to your sauce @valtteri trollface

valtteri11:11:18

So far my ‘avoidance-strategy’ has worked out well. 😄 Sooner or later I’ll hit the wall though.

danielneal11:11:18

I started with async-flow-fx and then ended up hitting a wall, and now have specific state machines (a map with current-state -> event -> next-state) for every individual flow. On one level it's a right pain, but on another level it's quite clear

danielneal11:11:37

I'm interested in any solutions in this space though

danielneal11:11:30

Not tried the alet solution - although I'd be interested to try, I'm just avoiding a big refactor at this stage

Macroz12:11:25

@danieleneal nice, so basically every handler calls to a state machine function to select the next dispatch

Macroz12:11:29

I wonder if anyone has extracted that approach to a small library yet

Macroz12:11:56

I guess there is a lot more convention than code in it though

danielneal12:11:35

I think with some thought and work it could be an interesting library

danielneal12:11:13

it's difficult to strike the right balance and avoid the inner platform effect

miikka16:11:43

I'm using callback-hell as well 😐

hoopes16:11:32

https://github.com/tomasd/statecharts i haven't used this in any level of anger yet, but it's a SC implementation targetted to re-frame

Macroz16:11:25

interesting :thumbsup:

danielneal16:11:37

oooh interesting @hoopes

Macroz16:11:45

looks quite complicated and becomes an exercise of programming in an internal DSL

danielneal17:11:33

hard to figure out where to start from the readme