How To Dispatch Two Related Events In a Re-frame Application?

867 Views Asked by At

I'm working on a game with inventory system. Right now, the characters equipment and inventory are separate values in my DB. My problem, is when a user equips an item I need to both remove the item from the inventory and add it to the character.

I have something like this right now:

(defn equip-item [item idx]
  (re-frame/dispatch [:equip-item {:position :off-hand :item item}])
  (re-frame/dispatch [:remove-item-from-inventory idx]))

(re-frame/reg-event-db
  :equip-item
  (fn [db [_ itemObj]]
    (update-in db [:character :equipment] merge {(:position itemObj) (:item itemObj)})))

(re-frame/reg-event-db
  :remove-item-from-inventory
  (fn [db [_ idx]]
    (update-in db [:inventory :main] handle-remove idx)))

This works perfectly fine so far, but I'm wondering if there's a better way to handle dispatching multiple events like this? I know there's an ability to create an effect with a :dispatch-n key, but I'm not sure if that's appropriate here.

In any case, I'm also concerned about one event failing with the other succeeding. These should behave sort of like a transaction in that if one fails they both should fail.

2

There are 2 best solutions below

0
On

Instead of using reg-event-db, use reg-event-fx. This returns a hash of effects.

One of these effects can be :fx, which is a list of other effects to call. These effects can be, for example, to dispatch an event. Some code:

(rf/reg-event-db
 :print1
 (fn [db]
   (.log js/console "print1!")
   db))

(rf/reg-event-db
 :print2
 (fn [db]
   (.log js/console "print2!")
   db))

(rf/reg-event-fx
 :test-two-dispatch
 (fn [{:keys [db]} _]
   {:db db
    :fx [[:dispatch [:print1]]
         [:dispatch [:print2]]]}))
0
On

The best approach would be to extract those update-in to separate regular functions, create the necessary third event, and call those functions in there via e.g. ->. Of course, you would call those functions in the original events instead of update-in as well.