Fork me on GitHub
#re-frame
<
2022-01-17
>
Noah Bogart17:01:06

continuing my adventures with “server-side re-frame”, i’m looking for a small code review. in normal re-frame, views are calculated by the app-db being a reagent atom cascading a series of subscriptions. this means that you don’t have to inform or generate any view-specific information in an event handler (`reg-event-fx`), you just make changes to :db and let the rest flow naturally. however, in my server re-frame, views don’t exist because how could they? instead, i have effect handlers that send the new/changed data to the clients (using websockets). that data has to come from somewhere, so I can either create it in the event handler and make the effect handler really simple (receive and send pre-generated data to clients) or in an effect handler (receive needed information, generate and send data to clients).

Noah Bogart17:01:08

Here’s an example of the former style event and effect handlers (don’t mind the reuse of send-event-list!, trying to figure out a better way to do all this):

(executor/reg-event-fx
  :lobby/list
  [executor/unwrap]
  (fn send-lobby-list
    [cofx data]
    (when-let [uid (:uid data)]
      (let [db (:db cofx)
            lobbies (:lobbies db)
            lobby (uid->lobby lobbies uid)]
        {:fx [[:lobby/broadcast-list (prepare-lobby-list (vals lobbies) [(uid->user db uid)])]
              (if lobby
                [:lobby/state (prepare-lobby-state lobby)]
                [:lobby/clear uid])]}))))

(defn send-event-list!
  [event-list]
  (doseq [[uid ev] event-list]
    (ws/chsk-send! uid ev)))

(executor/reg-fx :lobby/broadcast-list #'send-event-list!)
(executor/reg-fx :lobby/state #'send-event-list!)
(executor/reg-fx :lobby/clear (fn [uid] (ws/chsk-send! uid [:lobby/clear])))

Noah Bogart17:01:59

and here’s the same example, but where the conversion of db data to client data happens in the effect handlers:

(executor/reg-event-fx
  :lobby/list
  [executor/unwrap]
  (fn send-lobby-list
    [cofx data]
    (when-let [uid (:uid data)]
      (let [db (:db cofx)
            lobbies (:lobbies db)
            lobby (uid->lobby lobbies uid)]
        {:fx [[:lobby/broadcast-list [(vals lobbies) [(uid->user db uid)]]]
              (if lobby
                [:lobby/state lobby]
                [:lobby/clear uid])]}))))

(executor/reg-fx
  :lobby/broadcast-list
  (fn send-broadcast-list!
    [[lobbies users]]
    (doseq [[uid ev] (prepare-lobby-list lobbies users)]
      (ws/chsk-send! uid ev))))

(executor/reg-fx
  :lobby/state
  (fn send-state!
    [lobby]
    (doseq [[uid ev] (prepare-lobby-state lobby)]
      (ws/chsk-send! uid ev))))

(executor/reg-fx :lobby/clear (fn [uid] (ws/chsk-send! uid [:lobby/clear])))

Noah Bogart17:01:36

having written this out, maybe I didn’t pick the best examples, lol, but i think it works close enough

Noah Bogart17:01:04

(should have picked an example that changes :db)

Noah Bogart17:01:27

the underlying question is: how much pre-calculation should an event handler do before passing off to effect handlers?