3.0 KiB
Subscriptions Cleanup
There's a problem and we need to fix it.
The Problem
The simple example, used in the earlier code walk through, is not idomatic re-frame. It has a flaw.
The code is here.
You'll notice that it does not obey the re-frame rule: keep views as dumb as possible.
A view should never do any computation on input data. Its job is just to compute hiccup. The subscriptions they use should deliver the data already in the right structure, ready for use.
Just Look
Just look at the horror of it:
(defn clock
[]
[:div.example-clock
{:style {:color @(rf/subscribe [:time-color])}}
(-> @(rf/subscribe [:time])
.toTimeString
(clojure.string/split " ")
first)])
That view obtains data from a [:time]
subscription and then it goes to town
massaging that data into the form it needs for use in the hiccup. We don't like that.
The Solution
Instead, we want to use a new [:time-str]
subscription which will deliver the data all ready to go, so
the view is 100% concerned with hiccup generation only. Like this:
(defn clock
[]
[:div.example-clock
{:style {:color @(rf/subscribe [:time-color])}}
@(rf/subscribe [:time-str])])
Which, in turn, means we must write this time-str
subscription handler:
(reg-sub
:time-str
(fn [_ _]
(subscribe [:time]))
(fn [t _]
(-> t
.toTimeString
(clojure.string/split " ")
first)))
Much better.
You'll notice this new subscription handler belongs to the "Level 3" layer of the reactive flow. See the Infographic.
Another technique
Above I suggested this:
(defn clock
[]
[:div.example-clock
{:style {:color @(rf/subscribe [:time-color])}}
@(rf/subscribe [:time-str])])
That may offend your aesthetics. Too much noise with those @
?
How about we define a listen
function to clean it up.
(defn listen
[query-v]
@(rf/subscribe v))
Then we can re-write like this:
(defn clock
[]
[:div.example-clock
{:style {:color (listen [:time-color])}}
(listen [:time-str])])
At the cost of your own function, listen
, the code is slightly less noisy
AND there's less chance of forgetting an @
(which can lead to odd problems).
Say It Again
If, in code review, you saw this view function:
(defn show-items
[]
(let [sorted-items (sort @(subscribe [:items]))]
(into [:div] (for [i sorted-items] [item-view i]))))
What would you object to?
That sort
, right? Computation in the view. Instead we want the right data
delivered to the view - its job is to simply make hiccup
.
The solution is to create a subscription that delivers sorted items.
Previous: Infographic Up: Index Next: Basic App Structure