Fork me on GitHub
#re-frame
<
2022-11-02
>
valerauko05:11:45

Is it possible to use the output of one signal function as the input of another? Is something like the below possible with just reg-sub?

(rf/reg-sub
 ::item
 (fn [db [_ id]]
   (get-in db [:items id])))

(rf/reg-sub
 ::highlight
 :-> :highlight)

(let [hl-id @(subscribe [::subs/highlight])
      hl-item @(subscribe [::subs/item highlight-id])]
  ,,,)

p-himik07:11:38

Apart from the hl-id/`highlight-id` typo, your code should work just fine. That's a pattern that re-frame documentation itself often uses.

valerauko09:11:13

Doesn't this make the component it's used in re-render at every db change? I'd hoped to make a subscription that somehow combines ::highlight and ::item (pipe the result of highlight into ::item)

p-himik10:11:05

No, i twill be re-rendered only when either of those subs changes its value. Unrelated app-db changes won't result in re-rendering.

p-himik10:11:41

But you can still make a sub that combines those two. The simplest in this case would be to use reg-sub-raw.

valerauko10:11:01

> re-rendered only when either of those subs changes In that case it's moot. Gonna just combine them in the view. I checked reg-sub-raw, but as the name suggests it's pretty raw.

p-himik10:11:27

It's not a downside though.

(rf/reg-sub-raw ::highlighted-item
  (fn [db _]
    (r/reaction (get-in @db [:items @(rf/subscribe [::highlight])]))))

p-himik11:11:04

Or:

(rf/reg-sub-raw ::highlighted-item
  (fn [_ _]
    (rf/subscribe [::item @(rf/subscribe [::highlight])])))

Absolute Negativity09:11:14

Looks like I have shot myself in the foot by having a lot of "view", domain-logic functions taking db liberally. The pieces are very flexible. But now any subscription I made of them will invoke them every time db changes. Do you guys clearly separate simple getter functions (db -> not-db) from computation functions (not-db -> not-db)? It will be a major re-factoring for me. Is there any clever solution here?

p-himik10:11:10

Views shouldn't care about the internal app-db structure. I like the approach where you have two kinds of data - one is the domain data (things you'd put in a relational DB) and the other is the app data (current user, current panel, active dialogs, etc.) For the first, I store the data in a specific normalized way and query it using some specific subs that are common for all views and data entities. The sub is called just :q. For the second, I create ad-hoc subs for every necessary value with a reasonable level of granularity.

Absolute Negativity14:11:25

Thanks. Actually, the shape of my problem looks very much as follow:

(defn foo-a [db a]
  (let [b (some-computation-a db a)]
    (foo-b db b)))

(defn foo-b [db b]
  (some-computation-b db b))

(f/reg-sub ::foo-a
  (fn [db [_ a]]
    (foo-a a)))
I guess I'm looking for ways to run less computations without having to refactor too much. What do you think?

p-himik14:11:58

It's a reasonable approach to refactor all your subs and events into functions with similar input/output shapes with actual handlers just combining those functions. And it can be a gradual process, which is nice.

Absolute Negativity15:11:54

I've solved my problem! I think my question wasn't clear. My namespaces are actually already separated into clear domains. And so, I can use information about each domain to limit the scope without changing any structure!

(f/reg-sub :select-keys
  (fn [db [_ keys]]
    (select-keys db keys)))

(f/reg-sub ::get-value
  :<- [:select-keys #{:data :updated-data}))]
  (fn [db [_ data-path opt]]
    (utils/get-merged-value db data-path opt)))
Thank you.

👍 1
MegaMatt15:11:53

is :-> a thing? I use :<- but haven’t seen what valerauko posted before

💪 1
p-himik16:11:10

It is. It's in the docstring of reg-sub. There's also :=>.

dvingo16:11:54

yep https://github.com/day8/re-frame/blob/5cfc9b8ec00aa4275b1716b9d453e41cf04495a6/src/re_frame/subs.cljc#L173 simply removes the args so you don't get edge cases where a keyword doesn't exist in add-db returning the arguments to the subscription

MegaMatt16:11:32

oh nice. thanks