ClojureScript Re-frame subscription dereferencing dilemma

569 views Asked by At

What's the best of following approaches?

Outer subscription, early deref

(defn component [msg]
    [:p msg]))

(let [msg (rf/subscribe [:msg])]
    [component @msg]

Outer subscription, late deref

(defn component [msg]
    [:p @msg]))

(let [msg (rf/subscribe [:msg])]
    [component msg]

Inner subscription, early deref

(defn component []
   (let [msg @(rf/subscribe [:msg])]
      [:p msg])))

Inner subscription, late deref

(defn component []
   (let [msg (rf/subscribe [:msg])]
      [:p @msg])))

When I keep the inner component pure using outer subscription, I can end up with many arguments that need to be passed through deeply nested structure of often unrelated parents. That can easily become a mess.

When I subscribe inside inner component, it becomes impure, losing easy testability.

Also, I wonder if there is an important difference between early and late dereferencing, other than I have to pass reagent/atom when testing the latter.

2

There are 2 answers

1
Mike Thompson On BEST ANSWER

We'll the answer, as always, is "it depends", but ...

Outer subscription, early deref leads to pure/testable inners. So that could be a good choice when that's important to you. But we don't use this style much.

Outer subscription, late deref we've actively moved away from this style because it produced code which we later found hard-to-understand. BTW, if ever we do pass ratoms/cursors/subscriptions around, we like to put a trailing * on the argument name to make it clear they are a reference-y thing, and not a value.

Inner subscription, early deref is probably the most used, I'd guess. Feels very natural after a while. Perhaps use <sub from LIN

Inner subscription, late deref this works too, but I tend to prefer the variation directly above. There's always a nagging worry that you might forget to add @ at the point of use, and that can be an annoying bug to find.

0
Michiel Borkent On

Don't know if this solves your dilemma, but since Re-frame 0.9 you can write @(rf/subscribe [:msg]) wherever you need a value from the subscription. Subscriptions are cached, so creating many using the same path doesn't yield more than one subscription. More information in this blog article: https://lambdaisland.com/blog/11-02-2017-re-frame-form-1-subscriptions and this Re-frame issue.