Fork me on GitHub
#re-frame
<
2022-10-03
>
pez16:10:35

I have an event handler with a cofx that creates an object, and I want to store a reference to this object in the app-db. It's not obvious to me how to achieve this. Should I dispatch in the reg-fx function?

p-himik16:10:25

If the event is registered with reg-event-db, you just return the new app-db value, so all you need to do is add that object to it and return it. If you used reg-event-fx, then you need to return a :db effect with that new app-db value.

pez16:10:38

Thanks! Maybe I am doing this wrongly... I'm doing something like so:

(rf/reg-fx
 :foo/create-a-thing!
 (fn [thing-data]
   (js/fw.Thing. thing-data)))

(rf/reg-event-fx
 :foo/thing
 (fn [{db :db} [_ thing-data]]
   (let [new-db (assoc-in db [:foo :thing] thing-data)
         already-created? (get-in db [:foo :thing-created?])]
     (merge {:db new-db}
            (when (and (not already-created?) thing-data)
              {:db (assoc-in new-db [:foo :thing-created?] true)
               :foo/create-a-thing! thing-data})))))
Instead of already-created? I would like to store the object.

p-himik16:10:47

Hold on. In the OP you say: "a cofx that creates an object". "Cofx" stands for "coeffect", and coeffects in re-frame are things registered with reg-cofx and that make their way into the context right before event handler that use those coeffects are called. Usually, you use them via the inject-cofx built-in interceptor. But in your code above, you're creating an effect. Usually effects are used for side-effects, it's a way for re-frame to make event handlers talk to the outside world, in a way. The :db effect changes the app-db, the :dispatch effect dispatches a new event, and so on. So in your case, if (js/fw.Think. ...) does not side-effect, I'd just construct it right in that event handler and put it in the :db right there, without any [co]effects. If it doesn't side-effect but you still want to keep it separate for some reason, then put it in a coeffect. And if it does side-effect, put it in its own effect, just the way you're doing it above, but restructure the effect in such a way so that it changes app-db. Not directly, of course, but via some event created specifically for the thing. That's needed because return values of effects are ignored - their sole purpose is side-effects.

pez19:10:30

Yeah, sorry, the terminology has never really landed right with me. I read this in the docs from reg-event-fx and thought I was registering a cofx:

Example Usage:

      #!clj
      (reg-event-fx
        :event-id
        (fn [cofx event]
          {:db (assoc (:db cofx) :some-key (get event 2))}))   ;; return a map of effects
Anyway, instantiating fx.Thing side-effects a lot, so maybe it makes sense to put it in an effect? If so my question actually is how I: > restructure the effect in such a way so that it changes app-db. Not directly, of course, but via some event created specifically for the thing. Should I dispatch that event from :foo/create-a-thing!?

p-himik20:10:07

Yep, exactly.

(rf/reg-fx ::create-thing
  (fn [data]
    (let [thing (js/Thing. data)]
      (rf/dispatch [::-store-thing thing]))))

(rf/reg-event-db ::-store-thing
  (fn [db [_ thing]]
    (assoc db :the-thing thing)))

(rf/reg-event-fx ::do-stuff
  (fn [{db :db} [_ data]]
    {:db ...
     ::create-thing data}))

pez20:10:28

Thanks. That works like a charm.

👍 1