This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-03-20
Channels
- # beginners (7)
- # boot (39)
- # braid-chat (3)
- # braveandtrue (1)
- # cider (27)
- # cljsjs (15)
- # cljsrn (6)
- # clojars (18)
- # clojure (307)
- # clojure-art (1)
- # clojure-brasil (1)
- # clojure-italy (2)
- # clojure-poland (3)
- # clojure-russia (61)
- # clojure-sdn (2)
- # clojure-taiwan (4)
- # clojure-uk (5)
- # clojurebridge (7)
- # clojurescript (19)
- # core-async (1)
- # core-matrix (1)
- # cursive (35)
- # datomic (3)
- # emacs (51)
- # euroclojure (3)
- # hoplon (20)
- # jobs (1)
- # keechma (1)
- # mount (3)
- # off-topic (2)
- # om (177)
- # onyx (96)
- # parinfer (4)
- # pedestal (4)
- # re-frame (19)
- # reagent (7)
- # untangled (5)
Hi, debugging question: I have a situation where a component isn't updating after a mutation. Likely, I need to put in better "read queries" after the mutation to get it to update properly. However, it would be awesome if there was a way I could just tell OmNext "Just always update everything after a mutation" to basically turn off the "optimized updating" that the indexer performs- This would give me valuable debugging information. Is there any way to do this? Thanks in advance!
also, I learned today that you can see the actual queries om will do with (om/transform-reads reconciler tx)
@tomjack: Yes, I agree that should work, but I was hoping there was a way to just do it globally with a flag, because I have a sneaky suspicion I'm running into an OmNext bug and having a way to "turn off OmNext's optimization brain" directly might be a better way to track that down.
@tomjack: Good point about transform-reads
, I hadn't given that one a close look yet, probably would be wise for me to study it very closely.
I don't guess there is any way to turn off its brain. if om/touch! were implemented already (there is a todo issue for it), you could maybe call it yourself after a mutation
@tomjack: LOL that's kinda what some of my code looks like right now, and I'm trying my darndest to stop doing that kind of thing by getting to the bottom of my refresh issues
(defmethod mutate 'mutate/update
[{:keys [ast state ]} key _]
{:remote (assoc ast :params {:some-param (get @state :some-stuff)})})
@danielstockton: I was also hitting an error when merging remote state with alpha-31 and datascript. To fix my error I had to set :migrate nil
in my reconciler(s). I hope this works for you
@iwankaramazow: for some reason, if I don't return {:remote true}, things doesn't work
@iwankaramazow: I was trying to return {:remote ...} with very different values and none worked, but now that i've returned the ast, it does work. Why?
@thiagofm: It's either {:remote true}
or {:remote ast}
@iwankaramazow: how do you know those things? 😛
@thiagofm: I think I read in the tutorials/Tony.Kay's tutorial
aside from that, blood, sweat & tears 😛
I am also using datascript. I first tried state = conn but my transact used to fail with No queries exist
. Then I used {:conn conn}
. It is working well for me. May be that will help some one.
I had also set :migrate nil but I don’t need to do that now. Don’t remember what changed that
@tawus: do you have any example of all this? I guess I'm still struggling my way out to do remotes using datascript
Are IQueryParams meant to be static? In the sense I can't change whatever I've specified, like: static om/IQueryParams (params [this] {:language "ruby"}) So, query params will always be ruby. Is this useful? There could be the possibility to change the params to something else, or specify them by the caller of the component, is this possible?
@thiagofm: you can update them through set-query!
or update-query!
@iwankaramazow: But I need the component to do that, so I can't do it inside render
I feels a bit weird, if I pass computed props to a component, it doesn't care about it in IQueryParams or IQuery, it's not even accessible from that point
Example?
I think computed props are meant for callbacks
In Item, there's a IQueryParams (params [this] {:name "Item K"}) and IQuery with [:abc {:name ?name}]
just like you would transact a mutation
If I do: (render [this] (let [github-repositories (:language (om/get-computed this))] (om/set-query! this {:query {:a 1}}) (dom/div nil github-repositories)))) I see nothing in the read of that component (I don't see {:a 1})
Example, I'm printing everything in the read and I see no {:a 1}: (defmethod read :remote/github-repositories [{:keys [state query ast]} key params] (let [language (:language params) github-repositories (d/q '[:find ?e . :where [_ :remote/github-repositories ?e]] (d/db state) query)] (if (nil? github-repositories) (do (.log js/console "Github repositories read:") (.log js/console (pr-str github-repositories)) (.log js/console (pr-str query)) (.log js/console (pr-str params)) (.log js/console (pr-str state)) (.log js/console (pr-str key)) (.log js/console (pr-str ast)) {:remote (assoc ast :params {:language language})}) {:value github-repositories})))
Yea but you change the query of that component to :a
your parser will read :a
So, I need to specify the whole query, like: https://gist.github.com/thiagofm/4db7ffce772b08167797 ?
Whenever I do set-query! in my component, I start getting the following error: Uncaught #error {:message "No queries exist for component path (haxlife.components.window/Window haxlife.components.window/GameWindow haxlife.components.code/Code)", :data {:type :om.next/no-queries}}
@thiagofm: Not sure my code is going to help . Here is how I proceeded after struggling for some time. I had a small project I wanted to move to om.next.
I don’t use remote reads. I use a “read mutation” to load data into the datascript
db at load.
I merge results from mutation into datascript
using datascript
transact
.
I use a simple pub/sub with mutation to have a callback after mutation
in case local state needs modification (in case of errors in form).
I have put all this code into om-hack.cljs
to keep telling me that it might not be the right way to do it and as I learn more I have to fix them.
It is working well for me. If you still need the code of my om-hack.cljs I can send you that in a private message.
@tawus Hmm, I'm always using transact and normal datalog queries, does it answer your question? 😛 I like your approach!
@tawus: I just wonder why set-query! isn't working as expected... Can't see the correlation with this and datascript
With a mutation I guess it would be easier, I can just mutate whenever I load the component and handle everything by myself
Kinda regretting the fact I've picked datascript. I don't even need any fancy query. Everything I need is a key/value storage
Here is my take. om.next
uses state to store queries in :om.next/queries
. It uses get-in state [..]
to retrieve the data from state but for datascript
conn, it returns a datom which causes nil and hence the error.
You can avoid that by using idents
but then you have to overuse them and it is not pleasant
It's just one, I can comment it well and refactor it later if datascript gets more adoption
@thiagofm: that error means the root query is somehow invalid, in 99% of cases this means you're 'stealing' a query from a component and things don't compose
yea @iwankaramazow my issue yesterday was a root query that looked like [{:thing [:id] (om/get-query Legend)]
@haywood: Makes sense, because [{:thing [:id] {:legend [:id]}}]
isn't valid.
It's either [{:thing [:id {:legend [:id]}]}]
or [{:legend [:id]} {:thing [:id]}]
my legend component didn't have a legal query by itself, because it was just (query [this] {:legend [:id]})
@haywood: you only notice these illegal query errors after mutations because they are currently only detected in full-query
I've been thinking about ways to add invariants that detect this sooner
after you run a mutation, Om calls reconcile!
this in turn calls the component's full-query
in default-ui->props
the full-query
is computed with the help of the indexer
if the query paths or data paths are not valid, there'll be an error
or rather, if there are no data paths between the components' queries
[{:some/join [:some/key]}]
if you take this query, and [:some/key]
is the query of a component, and its parent has [{:some/join (om/get-query OtherComponent)}]
there's a path between the parent and the OtherComponent
and the path is [:some/join]
damn thank you for explaining that, I fixed the issue without understanding fully what was happening
now problems arise when you have something like [(om/get-query OtherComponent)]
in the parent
in this case there's no path between the parent and the OtherComponent
because you're stealing queries
this will just not work, and cause you problems down the road
alas, it's not a valid way to compose queries, because both parent and child end up with the same queries
¯\(ツ)/¯
so what's the exact difference between get-query vs full-query? (relative vs absolute)
Full-query uses the indexer?
@iwankaramazow: using a different example:
(defui Child
static om/IQuery
(query [this]
[:foo :bar]))
(defui Parent
static om/IQuery
(query [this]
[{:child/one (om/get-query Child)} {:child/two (om/get-query Child)}]))
(defui Root
static om/IQuery
(query [this]
[{:root (om/get-query Parent)]))
we can agree that the root query is: [{:root [{:child/one [:foo :bar]} {:child/two [:foo :bar]}]}]
however, if you (get-query Child)
, you'll get [:foo :bar]
if you instead get the full-query
of an instance of Child
you'll get [{:root [{:child/one [:foo :bar]}]}]
if it's in the :child/one
path and [{:root [{:child/two [:foo :bar]}]}]
if it's in the :child/two
path
that's the absolute query
which is also focused along the given path
Ah totally make sense
Thanks!
whats the om equivalent of https://github.com/reactjs/react-router
@adamkowalski: Om (next) is alpha, has few add-ons at the moment, and does not try to solve routing issues. This is a topic that comes up a lot. There are various examples of people doing routing, but the basic answer is: you do it yourself.
I’m not remembering what links there are to solutions, but you might search the web for examples.
@adamkowalski: FWIW, I've written about different ways to implement routing in Om Next http://anmonteiro.com/2016/02/routing-in-om-next-a-catalog-of-approaches/
Thanks, those sound like solid ideas. I do think that one thing the om community really needs is a https://js.coach/react equivalent
that way we could create a catalog of reusable components that could help standardize the different approaches people take to different problems.
@michaelr: that's too generic a question
could you give more context?
sure, it's a react native app.. i created the reconciler with the parser entry, also defined some components with queries. the component is rendered.. but i don't see any of the debug prints in the parser read function being called
@michaelr: well your parser is not called because the root component doesn't have a query
interesting.. is this documented somewhere? i think i missed it while reading om.next docs today
@michaelr: not sure where it's documented
but queries must compose to the root
that a query in a component down the UI tree won't get picked up
the root component must have knowledge of it
@michaelr: if you have a query [:foo]
in e.g. a Child
component
you must compose it to the root with e.g. [{:child (om/get-query Child)}]
If you're new to Om Next, I encourage you to go through the tutorial on the wiki
Think of composing queries as a graph where every node somehow connects to your root component
the om/get-query
part gives you the query composition
there's also a tutorial at https://awkay.github.com/om-tutorial
I think it's more comprehensive and beginner-friendly
so in practice i should always compose the child component's queries in the parent up to the root component
exactly
one important part is the fact that you can't 'steal' queries from a child-component
(defui Child
static om/IQuery
(query [_]
[:some/property]))
(defui Parent
static om/IQuery
(om/get-query Child))
Parent
steals the query from Child
, this will result in some problems down the road
(defui Parent
static om/IQuery
[{:some/join (om/get-query Child)}])
This is the right solution to composing the queriesJust remember this one, gave me a lot of problems before I understood this 😄
You might think, oh this component just needs the exact same data as its child, I'm just going to take that query
that's a red flag
Either the child doesn't need a query -> pure function
or you compose the child's query in a join [{:some/join (om/get-query Child)}]
iwankaramazow: how should i compose if my root component doesn't need queries? same join
way?
your root component query should be the aggregate query of all of its child components
https://github.com/omcljs/om/wiki/Components,-Identity-&-Normalization#something-to-look-at
look at the rootview component
my root component is just a container for a single child component at a time, and this child component changes (depending on which screen the user wants to see). i wonder whether i should dynamically change the root component's query to only aggregate the current's child query?
I am seeing the mutate function being called multiple times (twice) on a single call to om.next/transact!, is this expected? I would have expected only a single call to the mutate function when om.next/transact! is invoked.
@symfrog: the parser is called once with target
set to nil
and once for each remote target
@anmonteiro: Thanks, I was hoping to communicate parameter validation errors back to the component that initiated the mutation by putting/taking vals in a shared async channel. Since the mutation function could be called multiple times, it would end up putting multiple values on the async channel for the same validation error. Is there a more idiomatic way of communicating errors back to a component that initiated a mutation in om next? I was also going to use the async channel for communicating errors in the send and merge functions back to the component during mutations.