re-frame - idiomatic usage for decorating entities?

92 views
Skip to first unread message

Colin Yates

unread,
Jul 24, 2015, 6:12:21 AM7/24/15
to ClojureScript
Hi,

I have a table component which iterates a list of entities and calls a row component passing in that entity. In concrete terms I have a bunch of 'customers' that contain a FK ID of their manager and I want to render the name of the manager.

I need to decorate that entity with other things (resolving names of linked entities for example) and I can see a number of ways of doing that (hack code warning):

[decorate the collection in a sub]
Have a subscription which returns the decorated entities. This subscription would use other subscriptions to resolve the ids:

(register-sub :results
(fn [db]
(let [raw-results (subscribe [:raw-results])
managers (subscribe [:manager/by-id])]
(reaction
(map (fn [row] (assoc row :manager-desc (managers (:manager-id row))) @raw-results)))))

The cost is that this subscription is re-evaluated for every row if either the raw-results or the manager changes.

[decorate the collection in the component]
(defn table-rows []
(let [raw-results (subscribe [:raw-results])
managers (subscribe [:manager/by-id])]
(fn []
(let [results (map (fn [row] (assoc row :manager-desc (managers (:manager-id row))) @raw-results)]
(into [:tbody] (map table-row results)))

The cost here is that the entire table is re-rendered every time either the managers or the raw-results change, however the table-row rendering should be short circuited for the non-changed rows.

[decorate the collection in an entity-specific subscription]
(register-sub :decorated-row
(fn [db [_ row]
(let [managers (subscribe [:manager/by-id])]
(reaction
(assoc row :manager-desc (managers (:manager-id row))))))

(defn table-row [_]
(fn [raw-row]
(let [decorated-row (subscribe [:decorated-row (row)]
[:tr [:td (:manager-desc @row)]])))

(defn table-rows []
(let [raw-results (subscribe [:raw-results])]
(fn []
(into [:tbody] (map table-row @raw-results))

This feels the cleanest and changes are scoped to as small a change as possible.

The fourth variation is the same as above except table-row doesn't delegate to a subscription rather it subscribes to the managers map and resolves it inline.

What do you all consider 'idiomatic' and most performant?

Thanks!

Colin Yates

unread,
Jul 24, 2015, 6:43:28 AM7/24/15
to clojur...@googlegroups.com
From Slack the answer is _not_ to do:

> (defn table-row [_]
> (fn [raw-row]
> (let [decorated-row (subscribe [:decorated-row (row)]
> [:tr [:td (:manager-desc @row)]])))

but rather:

> (defn table-row [row]
(let [decorated-row (subscribe [:decorated-row (row)]
>
> (fn [raw-row]
> [:tr [:td (:manager-desc @decorated-row)]])))

i.e. the let always goes outside the inner fn otherwise you get one subscription per rendering which isn’t what you want.

Thanks Mike and profil
> --
> Note that posts from new members are moderated - please be patient with your first post.
> ---
> You received this message because you are subscribed to the Google Groups "ClojureScript" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to clojurescrip...@googlegroups.com.
> To post to this group, send email to clojur...@googlegroups.com.
> Visit this group at http://groups.google.com/group/clojurescript.

Reply all
Reply to author
Forward
0 new messages