This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-11-07
Channels
- # alda (7)
- # beginners (4)
- # boot (108)
- # cljsrn (40)
- # clojure (24)
- # clojure-berlin (1)
- # clojure-dev (20)
- # clojure-russia (21)
- # clojurescript (115)
- # clojurescript-ios (1)
- # cursive (8)
- # data-science (5)
- # datascript (3)
- # hoplon (313)
- # jobs (1)
- # ldnclj (2)
- # off-topic (19)
- # om (115)
- # portland-or (3)
- # re-frame (9)
- # yada (2)
is this the right syntax for parameterizing a join? [({:dashboard/posts ~(om/get-query Post)} {:foo "bar"})]
without params, everything works fine; when i add them, any transaction results in “No queries exist…”
i’m not even looking at the params in the parser
@joshfrench: yeah could be a bug, something minimal would be nice and I can make a test out of it
@jannis: what does :poll/questions do in that transact expression? Seems not to be used. Sorry about time zone delay.
@simonb Its the way the app expresses which queries it wants to read again after the transaction.
If you transact from a component the queries for that component are rerun. But if the transaction affects keys that are not part of the component's query, you have to state that you want to reread them (or a subset of them).
@jannis This is really good to know! Thanks
You could pass a callback down from the root and transact in the root, in which case you could omit :poll/questions in the transact! call, because it's part of the root query.
@jannis yes, but I didn't know why to put it there. Was just trying everything I could to make this work, I must confess
@jannis would you mind sharing a callback example (some code)
from unofficial docs : https://github.com/awkay/om/wiki/Om-Next-Overview#case-2-derivedrelated-data
From the official docs, we have https://github.com/omcljs/om/wiki/Quick-Start-(om.next)#a-mutation-function
Mutations should return a query expression for the :value
. This query expression is a convenience that communicates what read operations should be followed by a mutation. Mutations can easily change multiple aspects of the application (think Facebook "Add Friend"). Adding the option :value
result helps users identify stale keys which should be re-read. The guiding principle here shares common goals with HATEOAS.
Callback examples here: all transactions here pass in no keys because App includes all affected queries already. https://github.com/Jannis/om-next-kanban-demo/blob/master/src/kanban/app.cljs
Aren't they linked?
(om/transact! this
`[(selections/update-radio {:name ~id :value ~new-value :type ~type})
:poll/questions])
(defmethod mutate 'selections/update-radio
[{:keys [state]} key {:keys [name value type]}]
{:value [:poll/questions]
:action ...
:value
is just a hint for developers. It states "these keys may be affected by the mutation". There's no guarantee the hint is correct. It's also not used by Om to rerun any queries after transactions.
After reading the docs, I thought it was a rule not to transact on things not in the component's query
@jannis, ok you put the callbacks them just before the (render...
, correct?
You can put them anywhere... inline/anonymous, some function somewhere, an JS object method, your choice.
@jannis this is beautiful piece of software
Are there tradeoffs in using callbacks "intensively" ?
@leontalbot: I usually only use callbacks when invoking a pure React component (one not wrapped in defui), which I'll pass from the defui component that invoked it. That takes care of 95% of the cases for me, the other 5% I have to pass a query addition to the transact call as it has an impact on components elsewhere in the tree.
I don't know that I would consider callbacks bad, but I think Om.Next, when using it for what it does well, doesn't require them all that often.
@bplatz Any example I could study?
Nothing stand-alone, but here is a simple example for a click event I just wrote. Just a key in a map I pass with other stuff to a function that returns a standard React component: {:close-fn #(om/transact! this `[(ui/quickview-close ~{:id id})}
This is within the (render [this] ...)
function of a defui
component. So 'this' in this case will refer to the parent.
Understanding Clojure quote syntax should probably be a pre-requsite for om.next, as it gets used quite a bit in your transactions. Namespacing your transactions is a helpful practice, else the backtick will namespace it for you... you need to prefix it with ~' otherwise.
And this :close-fn is defined outside a defui?
" I usually only use callbacks when invoking a pure React component (one not wrapped in defui)"
I must say, it is still unclear for me what a pure react component is...
@leontalbot: an example of a pure react component: (def Button (js/React.createFactory js/ReactBootstrap.Button))
Got it
Thanks.
Hm. Running a version of my kanban demo built with :optimizations :advanced
and no source maps breaks om.next/transact!
calls. They throw the "No queries exist for this component" error, despite being executed in the root App
component, which has a query: https://gist.github.com/Jannis/cfb533ed03d304e346e6
this https://github.com/thheller/packages/tree/react-externs-reactcomponent fixed it for me
note that I am not running om.next
... so I have no idea if that fixes anything om.next
related
@thheller: your changes make sense. it looks like your changes conform to this line: https://github.com/facebook/react/blob/master/src/isomorphic/ReactIsomorphic.js#L48 which sets React.Component = ReactComponent and is included into the base react.fs file here: https://github.com/facebook/react/blob/master/src/React.js#L24
but I don't have a React app in production yet ... so I do not know why I'm the first to notice this error ... seems like someone should have run into this before
yeah if AFAICT no cljs React wrapper (other than om.next
) uses the ES6 class as well, it probably doesn't matter than
https://github.com/cljsjs/packages/pull/287 feel free to jump in .. I'm fairly confident that the changes are correct but independent verification would help
Have some people verified that 287 is good?
I’m happy to merge and push it if so
@martinklepsch: how can you test cljsjs packages is there a page about this somewhere?
@dnolen: check step 7) here: https://github.com/cljsjs/packages/wiki/Creating-Packages
@martinklepsch: cool thanks, in the middle of some other things but I will try this out later
@dnolen: thanks!
recursive queries coming along - it’s actually pretty cool https://github.com/omcljs/om/blob/master/src/devcards/om/devcards/core.cljs#L315-L328
@dnolen: The server-side parser returns {app/increment-counter [:app/counter]}
for a mutation [(app/increment-counter)]
that is (again, on the server-side) implemented with a readf
that returns :value [:app/counter]
(and an action). Am I understanding it correctly that your todo example simply merges that back into the app state using the callback passed to send
?
@dnolen I may have found a problem or inconsistency. Assume you have a read :app/counter
that returns {:value (get @state :app/counter) :remote true}
, a mutate 'app/increment-counter
that returns {:remote true}
and a server-side parser that handles these two, and a component that queries [:app/counter]
and triggers [(app/increment-counter)]
transactions.
When the query is first satisfied, it sends [:app/counter]
over to the server, receives the query result from the server (e.g. {:app/counter 5}
, merges it and reruns the query, this time returning the value fetched from the server to the component. All good.
When you perform the above transaction from within the same component, it sends it over, performs it, receives {app/increment-counter [:app/counter]}
, merges that, reruns the query, returns the local value but this time it doesn't also execute the query remotely. So you're stuck with the old value. Is this intentional? It does rerun the query remotely if the transaction is [(app/increment-counter) :app/counter]
(in this case the server returns {app/increment-counter [:app/counter] :app/counter 6}
) but I thought the keys queried by the component initating the transaction are always included implicitly. Shouldn't that also work with remote queries?
@jannis we consider the component as the thing which needs to re-read but we don’t magically know the keys that are involved as you are suggesting.
What exactly is different when the component re-reads after the transaction (which it does, but not the remote stuff)?
Sure. It does re-execute read :app/counter
after the transaction but only gets :value
out in that case?
right but the reason it executes that is because we can get the query from the component
I understand we can get the query from the component. But if we can call read for all keys in its query, can we not also execute the remote parts?
So ideally, you'd perform an optimistic mutation locally and revert if sending/executing it remotely failed.
it’s important to separate collection actions from operations on real logical entities (that have idents)
if you design your interaction around entities you should not have the problem you’ve just described
What if the component has an ident but doesn't pass it over to transact!
? Will the reconciler implicitly get its ident (instead of its query) after the transaction and refresh based on that?
I do find it a bit confusing though and I bet questions like this will come up again and again. Like "why no rerender after transact!
-> "oh, I have to add :foo/bar
to the call" (which I've answered about five times already ;)), "why is the remote state not re-read again after a transaction?" -> "oh, the component has no ident and doesn't add any of the affected keys to `transact!".
But perhaps the amount of confusion can be mitigated by documenting these scenarios very clearly, with examples.