This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-01-02
Channels
- # beginners (29)
- # boot (65)
- # cider (12)
- # cljs-dev (8)
- # cljsjs (31)
- # clojars (5)
- # clojure (147)
- # clojure-austin (47)
- # clojure-berlin (1)
- # clojure-brasil (7)
- # clojure-russia (5)
- # clojure-spec (18)
- # clojure-uk (18)
- # clojurescript (113)
- # css (2)
- # cursive (7)
- # datascript (5)
- # datomic (2)
- # dirac (4)
- # events (3)
- # funcool (143)
- # hoplon (287)
- # jobs (2)
- # off-topic (4)
- # om (10)
- # om-next (5)
- # onyx (18)
- # protorepl (1)
- # re-frame (93)
- # reagent (34)
- # rum (41)
- # test-check (51)
- # untangled (15)
- # yada (18)
@niwinz decided to give potok a shot, now wondering I have something that returns a promise, do you have an example how I would use that with WatchEvent
?
don’t like promises anymore? 😄
I like them but they are not silver bullet, rx observables are designed from the ground up to separate composition from execution
as you know, http requests are cancellable, and managing http request cancellation with promises is awful.
I have the pending task of release the httpurr library with promises replaced by observables 😛
I see, interesting perspective. You really are into observables haha
I searched the beicon docs for “promise” and similar but the from-promise
thing didn’t show up
ah ok, I thought the API docs were embedded in that page somewhere
sorry 🙂
So I now created a stream from the promise, now what’s the right way to do something when it succeeds/fails? For failures I use rx/catch
I guess? For success I use rx/map
? 😄
And another question: let’s say I want to log something for every event — How would I do that?
The beicon merge
example shows concat
: http://funcool.github.io/beicon/latest/#merge
Something that I think is really cool about re-frame is the ability to swap effect handlers for testing easily — have you developed any patterns to do similar things with potok?
So for stubbing out an event you just redef it?
I now ended up with something like this
(rx/merge (rx/just (->UiStart (hash this)))
(->> (rx/from-promise
(-> (js/firebase.database)
(.ref (str (name type)))
(.push (clj->js (get-in state (into [::ui] form-path))))))
(rx/delay 4000)
(rx/map (fn [x] (->UiDone (hash this))))))))
which does pretty much what I needmerge is not sequential, if you need to emit events in strictly order, rx/concat
can be used
later, the functions implements the update event, so you can emit them as is, without creating additional types
> later, the functions implements the update event, so you can emit them as is, without creating additional types Can you expand, I don’t think I understand
@niwinz order is not super important, just that an event is put on the stream as it becomes available
Interestingly when I replace merge
with concat
in the above snippet the UiDone
event is processed before UiStart
ptk/UpdateEvent
(update [_ state]
(js/console.log :UiStart (update-in state [::ui ::progress] (fnil conj #{}) op-id))
(update-in state [::ui ::progress] (fnil conj #{}) op-id)))
I’m sorry to be the conveyor of bad news 😄
Do you have any suggestion regarding the “log on every event” hook thing?
On uxbox, I define a own emit!
function that removes the need constantly pass the store on all the code
yeah, that seems to be a sensible approach
thanks
The question about testing/swapping “handlers” is still bugging me a bit but I’ll think about it some more
I think it’s a tradeoff of attaching the implementation to the message instead of having a kind-of registry that defines implementation
yeah, exactly
heh, that’s what I was just thinking about
on the other hand, the system is pretty flexible, I usually define events that does async stuff and other that does state transformation, each one with own constructors
I guess I could implement a registry that does
{:some-event (fn [ev-id ev-args]
(reify
WatchEvent
(watch ....)))}
not specify! infact but kind of similar
I think that’s an acceptable solution to this thought experiment for now 🙂
I have experimented in the past with splitted aproach (event and impl) and I found it too much mental overhead
How is it too much overhead? (Not used to the direct approach...)
in the last project when I have worked, the event and the impl was splited, events are defined as static constants and implementation are using some kind of register
this becomes very painful, constantly navigating through different files to understand the all the flow
having the event and impl in the same location, reduces considerably this pain, just reducing the number of files/namespaces to inspect.
in any case, potok is more than simple join of event and impl. the fact of using rx, helps on synchronize complex flows in a more "digestible" code
I think I understand what you mean but just technically splitting them doesn’t mean they need to be in different places. I can use a registry that refers to implementations that are located right where they’re used
@martinklepsch thanks for the feedback and your thoughts!
@niwinz you’re most welcome haha
Enjoying how much simpler Potok makes async stuff
So, decided to swap my own wonky xhrio thing for httpurr, now I’m struggling to understand how to properly put it into the rx machinery
(->> (rx/from-promise
(http/send! xhr/client
{:url "/get-friends"
:method :post
:body (->> {:url ""
:method :GET
:user-params {}}
(merge (get-in @app-db [:current-user :credentials :twitter]))
(clj->js)
(gjson/serialize))
:headers {"Content-Type" "application/json;charset=UTF-8"}}))
(rx/delay 2000)
(rx/map (fn [data]
(js/console.log data)
(->UiDone (hash this))))))))
This is what I have… I would have expected the error to be raised somewhere if theres a 4** but instead it’s just logged in the rx/map
step. Is that expected?@niwinz ^ any suggestions? 🙂
hey @martinklepsch, in httpurr
the responses that are 4xx and 5xx are not treated as errors (the server responded); the connection errors or timeouts are
Oh! that makes perfect sense and sounds like a very reasonable decision 👍
somehow missed that reading the docs/assumed it would be like clj-http et al
Agree, I very often use {:throw-exceptions? false}
when using clj-http
@dialelo in the example above I would use rx/map
to check the status code and then rx/throw
if I wanted an error to occur?
alternatively you can do it with promise's then
, something like (prom/then request (fn [response] (if (status/error? response) (prom/rejected "An error happened!") (parse-body response)))
alternatively, you can use this thin http client https://github.com/uxbox/uxbox/blob/master/frontend/src/uxbox/util/http.cljs
@niwinz that’s a good pointer, thanks
@dialelo using rx/throw worked like a charm
@niwinz one benefit of using a registry (and not vars) is that you don’t to require a namespace with the var you need and instead can handle that in one spot
@niwinz that makes it a lot easier to move event definitions around as well
oh and one thing: the tip you gave earlier… using (partial emit! …)
with some logging on top — it doesn’t support logging of events that are the result of WatchEvents
> "one benefit of using a registry (and not vars) is that you don’t to require a namespace with the var you need and instead can handle that in one spot" hmm, but in any case you will need to import ns where events are defined? I'm missing something?
> hmm, but in any case you will need to import ns where events are defined? I'm missing something?
Yes you still need to import them but through the registry indirection you could have a mapping of {keyword event}
and only provide to the keyword whenever you want to refer to the event
@niwinz if you end up thinking about logging I think it might also be nice to consider interceptors or a similar approach. I haven’t needed them a lot when using re-frame but they certainly seem very extendable and can easily solve issues like logging
I hope what I’m saying makes sense
I’ll try to experiment a bit as well
@niwinz not sure I understand, I need to do something with the result of the FirebasePush
event, rx/of has the same issue like rx/just, which is that data-snapshot
in the above snippet is just the FirebasePush record
I’m almost definitely approaching things from the wrong angle haha
and in order to fix it, just use rx/of passing each event as positional argument or call rx/from-coll with the same vector that you are returning
(->> (rx/just (->FirebasePush type (get-in state (into [::forms] form-path))))
(rx/delay 1000)
(rx/mapcat (fn [data-snapshot]
(js/console.log :data-snapshot data-snapshot)
(rx/of (->FirebaseDomainObject type (.-key data-snapshot) (to-clj (.val data-snapshot)))
(->UiDone (hash this))]))))))
I’ve been using mapcat like that the whole time 😄
let me try
So in your snippet data-snapshot
will still be the FirebasePush record and not the result of that event
I think my understanding is… lacking a bit 😄
@niwinz that’s very kind, thanks in advance!
Additionally, one thing that is pretty cool in potok, is that you can emit anything you want, it is not mandatory to implement any event protocols
i hope you find this useful @martinklepsch
Thanks for the detailed example @niwinz
after reading the potok docs earlier I remembered that this stream
argument to watch events was good for something