This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-03-04
Channels
- # aleph (2)
- # announcements (1)
- # biff (1)
- # calva (16)
- # cider (4)
- # clojure (45)
- # clojure-argentina (1)
- # clojure-europe (21)
- # clojure-nl (1)
- # clojure-norway (18)
- # clojure-uk (7)
- # clojurebridge (1)
- # clojurescript (3)
- # clr (3)
- # cursive (21)
- # datomic (4)
- # fulcro (4)
- # graalvm (3)
- # holy-lambda (8)
- # honeysql (22)
- # lsp (3)
- # malli (3)
- # nbb (1)
- # off-topic (3)
- # portal (13)
- # re-frame (3)
- # reagent (7)
- # releases (1)
- # shadow-cljs (1)
hey folks, apologies if this has been asked before but it's a little tricky to search for a concept.
i'm wondering if there's a better way to handle this scenario:
my goal is to expose interfaces to entities in my database only through subscriptions. i don't want to have to call a module's function and pass in the app-db. i exclusively want to use some well-defined, tightly controlled subs like
[:entities/the-thing-by-id {:id ...}]
. i think this helps decouple modules/namespaces and components, and generally keeps the whole system cleaner.this leads to an interesting (unlikable?) design choice :
suppose my app is handling a collection of stores, where each store has departments and aisles. because i'm only exposing access to my 'base entities' through subscriptions, it makes my specific component subscriptions kind of akward. i feel like the view knows too much about what's happening in the rest of the app (why should this component have to know there's even a concept of a 'selected store').
(defn render-a-store
(let [id @(rf/sub [:shared-state/the-selected-store])
store @(rf/sub [:entities/store-by-id id])
departments @(rf/sub [:component-state/store-departments id])
aisles @(rf/sub [:component-state/store-aisles id])]
[:div ,,,]))
;; what i have to do
(rf/reg-sub
:component-state/store-aisles
(fn [[_ store-id]]
[(rf/sub [:entities/store-by-id store-id])])
(fn [[store]]
(sort (distinct (map :aisles store)))))
;; what i want to do, or something similar to this: feed one input signal into another
(rf/reg-sub
:component-state/store-aisles
(fn [[_ store-id]]
[(rf/sub [:entities/store-by-id (rf/sub [:store/active-store-id])])])
(fn [[store]]
(sort (distinct (map :aisles store)))))
(defn render-a-store
(let [store @(rf/sub [:component-state/store])
departments @(rf/sub [:component-state/store-departments])
aisles @(rf/sub [:component-state/store-aisles])]
[:div ,,,]))
oh my goodness, this is exactly the point of reg-sub-raw
right? it would be something like:
(rf/reg-sub-raw
:component-state/store-aisles
(fn [app-db event]
(r/reaction
(let [active-store-id @(rf/sub [:shared-state/the-selected-store])
store @(rf/sub [:entities/store-by-id active-store-id])]
(sort (distinct (map :aisles store)))))))
now that i look at it, i kind of wonder if my sub-only interface to entities is going to force me to write a lot of more-busy reg-sub-raw functions 😞. i think i should reconsider the way my signal graph worksSeems that it could be made much better by having a subscription that returns the active store itself, and use that as a signal to other subs. What also helps is being able to define signal functions elsewhere to reuse them:
(defn <-active-store-signal [_]
[(rf/sub [...])])
(rf/reg-sub :store-aisles
<-active-store-signal
(fn [[store] _]
(sort ...)))