Fork me on GitHub
#re-frame
<
2023-05-03
>
Dr. Moltu16:05:22

hello, why the order of effects matter if they run asynchronously anyway?

p-himik16:05:45

Async != unordered. Order matters when effects depend on each other, implicitly or explicitly.

Dr. Moltu16:05:34

can you give an example?

p-himik16:05:50

The most obvious one is :db and :dispatch where the handler of the dispatched event expects for some value to already be in the app-db. Another example is where you have a :dispatch effect that changes app-db and e.g. some HTTP effect that relies on that change. In other words, preserving effect order allows for simpler composition.

Dr. Moltu16:05:35

ok I got it from the first example :db and :dispatch,

Dr. Moltu16:05:30

but the second how can :dispatch change app-db before http effect?

p-himik16:05:48

By using the :db effect.

Dr. Moltu16:05:06

when you say :dispatch effect, you mean {:fx [[:dispatch ...]]}?

Dr. Moltu16:05:13

but that's async and it queues while the http is already running

p-himik16:05:20

The effects aren't scheduled, they are executed immediately, right after a particular event is handled.

Dr. Moltu16:05:33

no not the effect, the event you :dispatch via :fx to update app-db will be scheduled

Dr. Moltu16:05:12

then the loop will continue to the next effect in the vec while the :dispatch is happening

Dr. Moltu16:05:24

if I understand reframe correctly

p-himik16:05:40

Ah, you're right. OK, my second example should be using two :dispatches then. :)

Dr. Moltu16:05:57

ok so the the two :dispatches will be scheduled in order right?

Dr. Moltu16:05:29

and that's important in re-frame, I mean the order dispatch was called, right?

Dr. Moltu16:05:54

not just the order in the queue

p-himik16:05:55

Re-frame preserves that order. Whether it's important or not depends more on the application itself.

p-himik16:05:04

Not sure what you mean by "on the view".

Dr. Moltu16:05:33

I mean the same execution context as the view

Dr. Moltu16:05:38

synchronously

p-himik16:05:52

The queue processing does not allow for interim renders unless you flush the DOM with Reagent. So regardless of the order, the views will see app-db changes only once the queue is empty again.

p-himik16:05:59

(Or the current batch - don't recall).

Dr. Moltu16:05:11

ok before the queue processing I mean, the enqueueing of events is in order

Dr. Moltu16:05:10

if we dispatch multiple stuff at the same time, theri call order will determine their order in the queue

Dr. Moltu16:05:47

+ sorry for so many questions : )

p-himik16:05:49

That's correct. Questions are fine, no worries. :)

👍 2
Fredrik Andersson18:05:17

Hi, I am trying to understand how I could use subscriptions that depend on each other. Like the signal graph documentation. However my problem is that I have multiple async actions that depend on each other. I have the following code:

(rf/reg-sub-raw :authentication-doc-id
  (fn [db]
    (-> (fire/call-function "clientLoginBankID" {:interface :admin})
      (.then #(rf/dispatch [:authentication-doc-id-updated (.-data %)]))
      (.catch #(rf/dispatch [:authentication-doc-updated %])))

    (ratom/make-reaction
      (fn [] (get-in @db [:login :authentication-doc-id]))
      :on-dispose (fn [] 
                    (rf/dispatch [:authentication-doc-id-updated nil])))))
                    

(rf/reg-sub-raw :authentication-doc
  (fn [db [_]]
    (let [authentication-doc-id @(rf/subscribe [:authentication-doc-id])
          unsubscribe
          (when (not (nil? authentication-doc-id))
            (js/console.log (str "Subscribing to authentication-doc " authentication-doc-id))
            (-> (fire/db)
                (fire/col "authentication")
                (fire/doc authentication-doc-id)
                (fire/sub 
                  (util/doc-snap #(rf/dispatch [:authentication-doc-updated %]))
                  (util/on-error #(rf/dispatch [:authentication-doc-updated %])))))]

      (ratom/make-reaction
        (fn [] (-> @db :login :authentication-doc))
        :on-dispose (fn []
                      (when unsubscribe
                        (unsubscribe)))))))
Where :authentication-doc should subscribe to a Firestore document with the ID given by the :authentication-doc-id subscription. This code does not work properly and I can't find examples that use nestled async subscriptions. Any pointers?

p-himik18:05:39

There is no such thing as async subscriptions. I'd suggest moving all impure things, all the "doing", into events. And make the subs do what they're designed to be doing - fetching and transforming data from app-db.

Fredrik Andersson18:05:52

Ok, I'm not sure when I should create the async operations. As far as I understand the events should be dispatched when the async operation is finished? (Sorry if I'm asking stupid questions. I'm new to re-frame)

p-himik18:05:24

Stupid questions are alright, but unless you have already read all of re-frame documentation, you should definitely do it. Any async operation is not different from e.g. the existing :http-xhrio effect or any other similar thing. You initiate some async workflow with an effect returned from an event handler. That effect handler receives some "continuation" events that it will dispatch in .then or using whatever async functionality you've got.

Fredrik Andersson18:05:33

Yes, I read it multiple times. It contains some new concepts that I'm trying to keep structured in my head. Ok, but those effects does not get triggered by a subscription? I thought it was quite a beautiful solution in my views just to subscribe to data and it will appear once the data is stored in the app-db.

p-himik18:05:38

Not recommended indeed - see the very start of that file, with "This document will soon be retired". It might be a beautiful solution but only superficially. It has its downsides and you have stumbled upon one of them.

Fredrik Andersson18:05:36

yes, but the thread refered to at the top wasn't really solving my problem

Fredrik Andersson18:05:25

I was confusing it with dynamic subscriptions

Fredrik Andersson18:05:45

I have missed those pointers. Will read. Thanks!

p-himik18:05:37

Also keep in mind that global interceptors exist. They make it handy to monitor a particular property value without you having to alter every single event handler that touches the value.

Fredrik Andersson18:05:21

Allright, haven't really dabbled with interceptors yet

Fredrik Andersson18:05:33

But I'll keep it in mind

Fredrik Andersson20:05:11

I need to use

(. js/navigator -userAgent)
and
(.. js/window -location -href)
Is it OK to use them in a subscription?

Nasiru Ibrahim15:05:18

Instead of the location.href, why not use reitit.frontend.easy/replace-state or push-state

Fredrik Andersson11:05:44

I do when I want to navigate. But i need this in order to send a back link to external app

Fredrik Andersson20:05:07

or would that mess up purity?

p-himik20:05:58

In an SPA, the second value can change without refreshing everything. If you use that value directly in a sub, that sub won't trigger a re-render of anything.

Fredrik Andersson20:05:12

you are right, however the value is combined with another value, so i suppose that it will be updated anyway. However, I thought that I should keep it in app-db, updating it along with the router event.

👍 2