Fork me on GitHub
#re-frame
<
2019-07-31
>
rgm16:07:25

Per my earlier question about visualizing a signal graph that has become spaghetti, here’s a hacky version of extracting it as data to feed into graphviz: https://gist.github.com/rgm/1b44f546c9ff7cccaeddb7b73d4a4291

rgm16:07:39

example signal graph output

4
🤯 4
🎉 4
rgm16:07:02

(yes, things are a bit out of hand here)

rgm16:07:19

has me wondering if there’s a less invasive way to do this via the registry

rgm16:07:34

it’d probably be useful to have this kind of viz for the other direction, where effects dispatch effects, to pick up eg. :dispatch, :dispatch-n and :dispatch-later effects.

oconn16:07:18

@rgm That’s cool - I’d add that to my projects (although I would probably be more interested in the other direction - event effects that call other events). For that, it may be possible to add an interceptor and tap into the after function, put it at the front of your chain and build up a graph after interacting with the app for a bit.

oconn16:07:43

or maybe replace do-fx

rgm16:07:59

Oh, that’s not a bad idea for that direction. It occurred to me too that since I’m defining the subs, I could make some higher-order fn that creates the signal-generating fn for an L3. Other than disconnected nodes (L2s that aren’t used by an L3) that’s where all the info is.

rgm16:07:39

this all has me seeing a ton of symmetry on event/effect flow and subscription flow, but there’s a weird lack of it on the subscription side in that there’s not really anything like interceptors (I don’t think)

Ashley Smith19:07:12

Hey everyone, I need some ideas. I'm trying to make an event which dispatches a notification if and only if the variable changes:

(rf/reg-event-fx
  :good-http-result
  (fn [cofx [_ result]]
    (println (str "Successful HTTP-GET: " result))
    { :db (assoc (:db cofx) :success-http-result result)
      :dispatch [:set-connection-status true]}))

(rf/reg-event-fx
  :bad-http-result
  (fn [cofx [_ result]]
    (println (str "Failed HTTP-GET:" result))
    { :db (assoc (:db cofx) :failure-http-result result)
      :dispatch [:set-connection-status false]}))

(rf/reg-event-fx
  :set-connection-status
  (fn [cofx [_ status]]
    { :db (assoc (:db cofx) 
                 :connection-status status)
      :dispatch [:new-notification 
                  ["Disconnected from server" "Please try again later." "is-danger"]]}))
So when a http request occurs, I want dispatch an event called 'set-connection-status' to keep an eye on the status of the last request. If this request CHANGES from false to true, I want to send a notification saying 'reconnected' or something, and likewise if it WAS true but is now false I want it to dispatch the event as shown above. I could make a complex sequence of events to force order, but I wanted to know if there's any techniques that I don't know about for doing something like this?

Ashley Smith19:07:11

I'm thinking I do a 'pre-set-connection-status' where I move the current status to a variable called 'last status', then in the actual 'set-connection-status' I then override the current variable and use the past and current value inside my dispatch function.. question is.. I don't know if this is the easiest way

oconn19:07:08

(rf/reg-event-fx
 :set-connection-status
 (fn [cofx [_ status]]
   (let [current-status (get-in cofx [:db :connection-status])]
     (cond-> {:db (assoc (:db cofx) :connection-status status)}
       (not= status current-status)
       (assoc :dispatch [:new-notification 
                         ["Disconnected from server" 
                          "Please try again later." 
                          "is-danger"]])))))

oconn19:07:18

I think that would do it

camden19:07:32

^ looks right to me, the idea is to conditionally add the dispatch effect if the status in the db is different from the status in the event

Ashley Smith19:07:01

okay let me study this as it's some new information to me

Ashley Smith19:07:35

So what really is the difference between cond-> and if, I know that -> just allows you to write things a little nicer, but is that the only reason here?

oconn19:07:02

You could write that with if but you’d be duplicating the :db value. cond-> differs a few ways but you can match multiple conditions and modify the threaded value for each truthy one.

Ashley Smith19:07:35

Okay! I think I got it! Thank you! So out of all of this, I didn't realise the fx registration was just a function, I thought it had to be a function which returned a map

Ashley Smith19:07:06

but that's very impressive that it is just a function!

manutter5119:07:30

It is just a function, but to play nicely with re-frame, it should return either a map or nil.

Ashley Smith19:07:02

I just tested it, it works perfect!

Ashley Smith19:07:08

Thank you everyone

manutter5119:07:19

by the way, cond-> is really useful if you need to build some kind of map that omits any keys that have nil values.

(defn make-opts
    [active? selected? modified?]
    (cond-> {}
            active? (assoc :active "active")
            selected? (assoc :selected "selected")
            modified? (assoc :modified "modified")))
=> #'user/make-opts
(prn (make-opts :active nil nil))
{:active "active"}
=> nil
(prn (make-opts nil :selected :modified))
{:selected "selected", :modified "modified"}
=> nil
(prn (make-opts :active nil :modified))
{:active "active", :modified "modified"}
=> nil

oconn19:07:59

So rf/reg-event-fx handlers do return maps. the result of

(cond-> {:db (assoc (:db cofx) :connection-status status)}
       (not= status current-status)
       (assoc :dispatch [:new-notification 
                         ["Disconnected from server" 
                          "Please try again later." 
                          "is-danger"]]))
will be {:db updated-db} or {:db updated-db, :dispatch conditional-dispatch}

☝️ 4
manutter5119:07:05

I only learned about it around a year ago myself, and it’s my new favorite Clojure function. 🙂

Ashley Smith19:07:05

I get it, I worked though it

Ashley Smith19:07:08

that's very powerful stuff

Ashley Smith19:07:25

I need to go and get some more lemonade while I digest it

manutter5119:07:51

to add on to what oconn is saying, it’s important to note that your reg-event-fx function can return nil, in which case nothing changes, but if your reg-event-db function ever returns nil, it will wipe out your app-db and give you some very strange symptoms.

manutter5119:07:20

and I’ll quit dumping information overload now. 😄

Ashley Smith19:07:02

because db must return the new app state?

Ashley Smith19:07:08

and nil = {} ?

manutter5120:07:23

Right, the reg-event-db function needs to return the new app-db state (or at least the old state), but the reg-event-fx function result goes to an internal function that basically says “If there’s a :db key then update the app-db value, if there’s a :dispatch key then dispatch an event, …” etc.

Ashley Smith20:07:08

I get it 🙂 thank you

👍 4
Ashley Smith22:07:23

This sounds dumb but so far I've only dispatched events during on-click and on interval.. Is there any way to dispatch an event on component load? I have a forum component which renders the forum, I want to send a http-get request to get some data and the subscribe for the response

Ashley Smith22:07:15

Can I just do

(defn forum
  []
  (rf/dispatch ..)
  (let [posts @(rf/subscribe ..
    [:div#forum
    ...
or is there a better way?

manutter5122:07:04

I think that one will re-dispatch every time anything inside the form changes (which may be what you want if your forum component only renders a read-only view of the current contents of the forum). If that's not what you want, you can achieve a one-shot dispatch like this:

(defn forum
  []
  (rf/dispatch ..)
  (fn []
    (let [posts @(rf/subscribe ..
      [:div#forum ...

manutter5122:07:36

Almost identical to yours except for the inner anonymous function, which re-frame will use as the rendering function every time the contents of the forum change.

Ashley Smith22:07:44

hmm, no I think the one shot dispatch is what I want, the user will refresh if tha'ts what they intend to do

Ashley Smith22:07:59

I was close!

😄 4