Fork me on GitHub

Hello to everyone on this channel. I was reading section "Components With Queries & Mutations". There is example of Counter component that consists of a label showing the state of counter and a button to increase counter. I wish to see reusing this Counter component and so I made a some changes.


At first render everything is ok. Labels show numbers as expected. But when clicked first two buttons there is no effect. When clicked last button it's counter value disappears.


What am I missing?


I found that click on any button increments count at the root of app-state-5. So something is missing in mutate function or in om/transact! call.


really curius about this one also. Appears like when you do the mutation afterwords the state is {:a (om/get-query Counter)} .


Your mutation is not updating :count under :a or :b so you would not expect the first two buttons to have any effect. transact! only triggers a re-render on the component it's called on, unless you pass in extra reads.


So every instance of Counter should have it's own mutate method? Is there any way to reuse Counter component to increase count fields in other parts of app state?


You could have a single method that accepts a path in the app-state to update as a parameter e.g. [(increment {:path [:a]})].


Can you @danielstockton, please, suggest how the above code should be changed so that every button increases it's own field (the same own it uses for reading)


Or how component can find it's own path to send in transact! call as parameter?


It's not that straightforward for the component to find it's own path, afaik. I would just restructure the app-state, giving each component an id, and then updating a count in a map under that id.


The id can be the key you use to join the query (`:a` or :b), in effect this is what you already have.


(defn mutate [{:keys [state] :as env} key {:keys [id]}]
  (if (= 'increment key)
    {:value {:keys [:count]}
     :action #(swap! state update-in [id :count] inc)}
    {:value :not-found}))


Then [(increment {:id :a})


@vitalije I’m new to clojurescript & om-next so might be wrong about this.


Using om/indent seems to be the way to reuse components so that om-next knows where the data is coming from


the only way I managed to make you’re example work is by calling the reconciler instead of the component. But that just re-renders the entire app and behaves like initial render.


[(increment) :a] should also work, saying "re-read queries of components that care about :a"


@claudiu I have tried your gist solution, but it still doesn't increase correct fields.


works for me. I modified the app-state and the read-function.


@claudiu Thanks. You have also changed id of the root DOM element so when I applied your code it didn't change the correct part of the page and I couldn't see the effect of your code.


However, it didn't solve my initial problem. I want component Counter to be usable for any count field in app-state not only on top-level fields.


I don't think that Counter component is too much usable but I just want to learn basics of creating self contained universally applicable components that could be passed query and it would act on that particular path.


showing and changing data on given path.


You have mention om/Indent, I will read it again.


@vitalije You can also pass through computed props (functions) to be called on particular actions. This way you can have a counter component accept an increment function without actually specifying the mutation to call inside the component.


@danielstockton I tried your mutate method and I have got it working once, but after first increment it stopped working.


I mean further clicks had no effect.


with om/get-computed


I have found that when I add path to the Counter components and in click handler pass that path to the 'increment function click on the button increases correctly path but than after re-rendering Counter it looses path information.


@claudiu Thanks you have solved it.


think the downside to using om/computed in over ident is that the mutation is in the context of the CounterGroup. Because of this om-next will read all the keys from CounterGroup (there was no need to specify fallow on read keys on transact).


will try to see if I can get it working with transact inside of the counter component and using om/ident 🙂


But it is not as I hoped to find. 😞 It means that user of Component must provide all the functionality. What good will be the Component then?


For rendering, unsing this approach


It makes the component more flexible to different app-state stores and schemas. There is nothing stopping you from hard-coding it in the component but it makes it less reusable imo.


like written now without ident, only the parent knows where the data is in the appstate 🙂 so the child can’t really update the state.


Again :) might be wrong. Still kinda new. Will also try to see how it goes with ident :)


I must leave now. Thank you all. If anyone make it using om/Indent I would greatly appreciate it.


Thank you @claudiu it works just fine.


Youre welcome :)