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!