This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-02-17
Channels
- # admin-announcements (3)
- # announcements (1)
- # aws (3)
- # beginners (41)
- # boot (109)
- # braid-chat (2)
- # braveandtrue (5)
- # cider (11)
- # cljs-dev (38)
- # cljsjs (15)
- # cljsrn (5)
- # clojure (87)
- # clojure-berlin (16)
- # clojure-ireland (1)
- # clojure-japan (10)
- # clojure-madison (3)
- # clojure-nl (3)
- # clojure-poland (6)
- # clojure-russia (115)
- # clojure-sg (1)
- # clojurebridge (35)
- # clojured (8)
- # clojurescript (36)
- # core-async (24)
- # cursive (18)
- # datavis (1)
- # datomic (27)
- # dirac (22)
- # editors (1)
- # emacs (3)
- # events (19)
- # hoplon (149)
- # ldnclj (7)
- # lein-figwheel (1)
- # luminus (1)
- # off-topic (70)
- # om (196)
- # onyx (63)
- # parinfer (155)
- # proton (36)
- # re-frame (69)
- # reagent (2)
- # ring (2)
- # ring-swagger (1)
- # slack-help (4)
- # spacemacs (9)
- # testing (11)
@anmonteiro: https://gist.github.com/eyston/cd9172cddb368b849750 is a small repro
a second question might be what is the right way to transact!
unique-idents
… do you transact!
:current-user
or [:current-user _]
. this is sorta big for us since if its :current-user
that gets filtered out by transform-reads
if its not mounted … I’m not sure how to transact!
unique-Idents
in a way that gets both sent to a remote always and updates the ui 😛
I’m afraid the second issue might be a design decision … that you can’t transact things that aren’t mounted
Hi, is it normal form a "read" function not to know what parts of the inner query are remote vs. local and then use the parser to query the inner joins to determine this? For instance, I have the following code:
defmethod read :retail
[{:keys [state parser query ast] :as env} key _]
(let [env (assoc env :retail (@state key))
remote-part (parser env query :remote)]
{:value (parser env query)
:remote (when (seq remote-part)
(assoc ast :query remote-part))}))
As you can see, it figures out the "remote-part" via the inner query- This code seems to work but also seems a bit ugly to me... can someone give me an opinion or suggest a way that I can do this in a cleaner way? Thanks!https://github.com/awkay/om-tutorial/blob/master/src/main/om_tutorial/parsing.cljs#L191-L204
can someone tell me why this doesn't work?
cljs.user=> (def state (atom {:foo {:bar true}}))
#'cljs.user/state
cljs.user=> (def state-cursor (om/root-cursor state))
#'cljs.user/state-cursor
cljs.user=> (om/update! state-cursor [:foo :bar] false)
#object[Error Error: No protocol method INotify.-notify! defined for type cljs.core/Atom: [object Object]]
Error: No protocol method INotify.-notify! defined for type cljs.core/Atom: [object Object]
at cljs$core$missing_protocol ()
at om$core$_notify_BANG_ ()
at om$core$notify_STAR_ ()
at om$core$transact_STAR_ ()
at $core$ITransact$_transact_BANG_$arity$4 ()
at om$core$_transact_BANG_ ()
at Function.om.core.transact_BANG_.cljs$core$IFn$_invoke$arity$4 ()
at om$core$transact_BANG_ ()
at Function.om.core.update_BANG_.cljs$core$IFn$_invoke$arity$3 ()
at om$core$update_BANG_ ()
cljs.user=> (def state (atom {:foo {:bar true}}))
#'cljs.user/state
cljs.user=> (def state-cursor (om/root-cursor state))
#'cljs.user/state-cursor
cljs.user=> (om/update! (om/ref-cursor state-cursor) [:foo :bar] false)
nil
cljs.user=> state
#object [cljs.core.Atom {:val {:foo {:bar false}}}]
@dnolen: hoping you could clarify something for me regarding the index building. I think I'm seeing a bug.
in the 2 queries below, are the prop->classes
index keys correct?
[:foo {[:current-user _] [:name]}]
;;=> #{:foo [:current-user _] :name} -> (shouldn't it be :current-user without the link?)
[:foo {[:users/by-id 2] [:name]}]
;;=> #{:foo [:users/by-id 2] :name} -> (shouldn't it be :users/by-id without the indent?)
@anmonteiro: for the later it should be the ident
@dnolen: I'm seeing 2 bugs then, I believe:
[[:users/by-id 2]]
;; #{:users/by-id} ;; Incorrect, should be the ident
[{[:users/by-id 2] [:id :name :age]}]
;; #{[:users/by-id 2] :id :name :age} ;; Correct
[{[:current-user _]} [:name]]
;; #{[:current-user _] :name} ;; Incorrect, should be #{:current-user :name}
[[:current-user _]]
;; #{:current-user} ;; Correct
Filing issue once you confirm this
@anmonteiro: sorry not following
let me try to clarify in the snippet
@dnolen: edited
@anmonteiro: ok, yes those are how it should be
thx for the clarification, filing issue
@dnolen: I've also been thinking if we could add an invariant that checks if components are stealing queries from each other
by looking at the indexes, I believe it should be possible
@anmonteiro: that would be very useful
I haven't put any time into actually proving we can do it, but I'll try to play around with it later today
I have a simple check but something stronger would be interesting (with the caveat that it doesn’t introduce more problems)
Yes, you do have a simple check in get-query
, I believe
but this is something that is only verified after the fact. If it were in build-index*
, feedback would be immediate
I can't confirm any of that from the top of my head without actually digging in
I'll make sure to watch out for those cases you mention nevertheless
after some more detailed profiling I discovered that db->tree
was only 10ms out of a 25ms query. I added more detail timing information and discovered that path->meta
is taking a lot of that time. It's called on the returned value, and because this is a top-level tabs component it's returning a big data structure when switching, which path->meta
is slow on. Looking at the source, I discovered the :elide-paths
option which fixes the issue, but what are the consequences of using that option?
@jlongster: it’s an expedient at the moment, there’s an existing issue which will be the real fix
@jlongster: David beat me to it: https://github.com/omcljs/om/issues/556
@jlongster: yes you could if you like, it’s not particularly hard
currently we blindly recurse instead of using the given query to figure out which parts of the data actually need to be traversed
I'm not entirely sure what the path metadata is used for, so I may not be able to fix it quickly. Not sure exactly what you mean, so I can just wait for a fix
one question, I was getting some weird errors when om was handling a response from a remote, I fixed it by returning the response as a vector instead of a list, my question is, does the list/vectore difference have a reason for the response? if so, is there a way to warn when the user returns the response as a list?
when I say list I mean {:value (...)} vs {:value [...]}
@jlongster: path metadata - it’s for the cases where we can’t for some reason use :pathopt
- the path metadata lets run only part of the query from the root and then just get what we need
@marianoguerra: it’s possible but the answer is more subtle than that
so a warning would need to look at the query to sort this out - so the right time to do this is durning normalization
@dnolen: ok, I'm finishing an example with frontend and backend and I will also document the problems I had and causes so people don't have the same
@jlongster: re: set-state! I can’t remember at the moment why I did it this way - but I recall there was some reason but I don’t have time to load it up right now
it may also be an oversight, but I did spend some time on it - looking at the source would probably clear things up
@jlongster: oh I know why
@dnolen: ok that's cool. It would neat if set-state!
could be used for optimization purposes like in this case
@jlongster: probably - would be a useful perf tweak
it seems sensible to me - you would just need to keep track of components who only get set-state!
call and no transact!
and then in the render loop in the reconciler just skip recomputing queries for these components
om.next includes the following functions: get-query
, get-unbound-query
, get-params
. Am I understanding correctly that get-query
works on component classes and instances, while the latter two only work on instances? I'm seeing the error Assert failed: (component? c)
when calling get-unbound-query
and get-params
on component classes.
I understand the docs are in incomplete and in flux, but it seems that they're not always consistent in distinguishing between component classes and component instances
Answering my own question: yes, get-unbound-query
and get-params
work on component instances only, not component classes.
@dnolen: now that one was definitely easy https://github.com/omcljs/om/pull/622
@jlongster: (require 'om.next.tests) (in-ns 'om.next.tests) (run-tests)
@anmonteiro: I get a "no such namespace" error. do I need to install om
any differently?
@jlongster: wait, how are you running them?
you can either run them at the Node REPL or the figwheel REPL
inside the Om project
without installing
tests are not installed, see: https://github.com/omcljs/om/blob/master/project.clj#L26
@anmonteiro: how do you start a figwheel REPL within Om? Sorry, I'm pretty new to Clojure's tooling
it's alright
rlwrap lein trampoline run -m clojure.main script/figwheel.clj
rlwrap
is not necessary
just for completion
I like to use it for cmd line history
@anmonteiro: what's the advantage of using lein trampoline run
as opposed to just lein run
?
trampoline spawns another process and kills lein
@anmonteiro: argh, sorry, so now figwheel is waiting for something to connect, what do I run in node to create a REPL environment?
lein run
doesn't kill lein
@jlongster: oh right, you need to point your browser to
to run the node REPL: rlwrap lein trampoline run -m clojure.main script/repl.clj
Actually, my understanding is that without trampoline
, Leiningen spawns two processes; one for itself and one for what it’s running.
@anmonteiro: aah cool, works now thanks
@akiva: yes, you're right
thanks, @anmonteiro @akiva
edited
@jlongster: cool will take a look later
@jlongster: to merge that will need a CA
@jlongster: I have your email, I’ll send you one now
@anmonteiro: not sure if at all related to the stuff you are looking at in the indexer, but that repro I sent you, if you notice the transformed reads end up being : [(user/update) {:thing-a []} {:thing-b []}]
so that works since it re-renders the components, but the actual field that changed is left out of the query which would screw with remote integration
@hueyp: I've submitted a patch that fixes it
do you know if that manifests itself on the transform-reads
stuff? I can try your PR out locally too~
the transform-reads
fn uses the indexes and they were getting built incorrectly
wrt to idents & links
just fired up the om-next todomvc project (with @anmonteiro 's pull request https://github.com/swannodette/om-next-demo/pull/2 ). Can't seem to add a new todo item (tried Safari and Chrome). Before I dig too much into it, anyone else experience this issue?
From the om.next docs: "render should return an Om Next or React component." Isn't that wrong? Shouldn't it return a React.Element (i.e., something like (om.dom/div nil "text") )?
According to my understanding: A component is a function that takes in props (among other things) and returns a React.Element. A React.Element is not a component.
@george.w.singer: very common to call those components, and refer to the type as a "component class"
@jlongster: Got it. Just making sure I wasn't missing something more fundamental
is there any heuristic about the length your queries should take (time) when I should start worrying?
i.e. some query takes 30msecs atm
Om flags a warning, optimize now?
@iwankaramazow: it’s just a way to hint that you should start considering :pathopt
and memoization where appropriate
ok, thanks!
@dnolen: there's something about updating queries that's been bugging me.
Let's say we have components Parent & Child. As expected, Parent uses (get-query Child)
If we set the child's query to a different one, reindexing will occur. What I'm seeing is that the indexes are not updated because when running the indexing from the root instance, get-query
won't see anything in -> state ::queries
for the root and will fallback on getting the class query, which in turn gets the query from Child's class.
@anmonteiro: right this is a known problem
this might have other implications downstream
the other approach is to have a query manager like thing, but I haven't had the time to work through whether that’s a good idea
though it hasn't been a problem for me yet, it seems like there could be distinct views on the queries of an app
depending where you look from
I'm happy to think about the problem, and bug you with questions down the road
the first one would be: is there an interest in keeping the original query?
@anmonteiro: I just don’t see how it can be all that useful, you can always get back to it via the class anyway
The most obvious pain point with the current approach is that full-query
returns wrong results at times
because it relies on the indexes
it seems to me that the indexes should be updated at all times
I'm thinking that if the query manager presents as a viable solution, queries could still be collocated and we'd manage the dirty manager stuff behind the scenes in defui
i.e. don't touch the current public facing API, but make it behave differently inside
I was curious about Relay, it doesn't look like it has an equivalent set-query!
does it? Surely there's some way to change the query, but I don't see it https://facebook.github.io/relay/docs/api-reference-relay-container.html
@jlongster: that link mentions setVariables
isn't that it?
@anmonteiro: I think that's just the equivalent to changing query params, not the query itself
you handle set-query!
query part in Relay at a root container, and then can set query params on any component
in om.next you might unmount / remount a new root or have a kind of indirection root component that does a switch on what to render … that is vaguely what the root container is doing
the other take in Relay is directives … you can make parts of a query conditional which get ignored via variables … include(if: $selected)
… which is something you might use update-query!
or set-query!
to do
I think ideally, like Facebook, has a single root per route … but using react-router-relay that didn’t match (router passes you children) so you end up with a relay root container per route ‘level'
@seanirby: answering your question, the ident seems correct but you need to compose the queries to the root
this means that the PeopleWidget query needs to get-query
the Person's query
anmonteiro: ah ok, I knew I was passing the raw data, so I need to pass a query instead. makes sense
you need to do both
query for the children's queries
and pass their props accordingly
I'm only talking about the defui
implementation
db->tree
is used to denormalize the data, but commonly used in your parser
anmonteiro: I get it now, you get the query for the paren'ts children in the parent's query.
What is the idiomatic way in Om Next to deal with event streams. For example in Elm you would have a notion of a signal which could represent a time varying value such as a mouse position, the window dimensions, what keys are being pressed, etc.
Should I essentially set global event listeners for the events that I care about, and then transact the latest information to the global app state atom?
for example every time the mouse is moved I would fire an event which would cause a transaction to occur which has a payload containing a vector with the current mouse coordinates?
@adamkowalski: It is my opinion that if you start firing different events according to what you're trying to do (mouse position, window dimensions, several keys) you'll end up losing control rather quickly
Hot code reload seems to have started to be less useful due to recent change to shouldComponentUpdate....forceRootRender doesn't re-render anything because S.C.U. returns false (since app state has not changed)
my approach would be to listen to those events and put all of them in the same core.async channel
and have one handler for all the events that dispatches on whatever you define
@anmonteiro: Seems to have stopped working with your change on 2/4