Reusing components

98 views Asked by At

Can someone please help me to better understand components, queries, etc. I'm struggling with a seemingly trivial task, I need one component with parametrized query. Instances of that component need to be included in a parent component, for example I want lists of different kinds of fruits that need to be distributed among group of kids and each row would show kid's name and a quantity of fruits of one kind:

  (defui FruitsLedger

    static om/IQuery
    (query [this]
      '[(:data/fruits) {:kind ?kind}])

    Object (render [this]
            (let [{:keys [data/fruits]} (om/props this)]
              (dom/ul nil (apply #(dom/li nil (str "for " (% :kid) " " (% :qt))))))))

now I need to have let's say two instances of this component in another component

where :params

for the 1st instance would be: {:kind :apples}

for the 2nd instance would be: {:kind :oranges}

this should render 2 lists similar to this:

  | apples        | oranges       |
  |---------------+---------------|
  | for Aaron 2   | for Katie 1   |
  | for Dan 1     | for Rob 3     |
  | for Charles 0 | for Charles 3 |
  |               |               |
  |---------------+---------------|
1

There are 1 answers

0
Chris Murphy On BEST ANSWER

I'm sure that parameterized queries have their uses. But perhaps this problem and other similar ones can be solved without resort to them.

Have :app/fruit-query-kinds in your db (default db format). It will be a list of fruits. You already have the fruit component, but you will need another component that has this idea of being a list of fruit kinds for querying purposes. Give this component a query and an ident. It doesn't matter if it is going to be displayed or not. Most important thing is getting the data structure right. Its ident will just be something like: '[:fruit-query-kind/by-id 1100], and it might consist of '[:fruit/by-id 10] and '[:fruit/by-id 20]. As per your example 10 will be the id for apples and 20 for oranges. That will be the refs value (a vector of idents in default db storage) of the key :app/fruit-query-kinds. 1100 is just a unique number that won't be expected to change.

The data structure is the important thing, and everything can be modelled in it, even query parameters.

You will need mutations and some buttons (or other input) that call transact! somewhere that directly change the fruit query kinds in your db. If you don't need any re-rendering to happen call transact! with the app's reconciler rather than with a component.

The idea is that you can then have component/s that query on the choices previously made by the user. So your first list component there won't know that it is to be for apples - all it knows is that it is to display fruits of the first fruit query kind.

I've found that you can do as much to-ing and fro-ing between the view and the db as you like, having the db not just store data but the current state of the view. So far the only time I got into trouble with this was when I mistakenly transacted on the not of the boolean key in the component's query. That of course ended up in a forever flickery screen.

In my opinion the way to work simply with Om Next on the Client is for all your reads to look exactly the same, all using db->tree. Once you accept this approach the next step is to get rid of them all together, which you can do by switching to the Untangled framework.