This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-04-29
Channels
- # admin-announcements (1)
- # aws (10)
- # beginners (76)
- # boot (53)
- # braid-chat (1)
- # cider (80)
- # cljs-edn (3)
- # clojure (65)
- # clojure-belgium (2)
- # clojure-gamedev (2)
- # clojure-nl (3)
- # clojure-poland (1)
- # clojure-russia (39)
- # clojure-uk (14)
- # clojurescript (91)
- # cursive (62)
- # datascript (1)
- # datomic (9)
- # dirac (34)
- # emacs (25)
- # error-message-catalog (8)
- # events (1)
- # hoplon (88)
- # instaparse (1)
- # jobs (2)
- # jobs-discuss (6)
- # lein-figwheel (7)
- # luminus (43)
- # mount (5)
- # off-topic (7)
- # om (28)
- # onyx (61)
- # planck (4)
- # re-frame (27)
- # reagent (3)
- # remote-jobs (2)
- # spacemacs (3)
- # untangled (136)
With respect to configuration: I'd prefer different config components if you have specific requirements. If there is a problem overridding the one we supply, then a PR on that is fine.
I guess if what you are wanting is to be able to put things like :env/DB_URL
into a config file and have those override at start that would be ok. I don't remember, @adambros , if we allow putting the application config in resources. We don't want that for our purposes, but loading it from classpath is technically trivial...so we could allow (if we don't) the production config to exist in resources. I'd want a little of the protection of "you have to say where the config is (e.g. -Dconfig=)" so it cannot be started in production accidentally without a config.
hello, I have a Root component that initially displays people well from app state that looks like this:
{:people [[:person/by-id 1] [:person/by-id 2]]
and the component is defined by starting with:
(defui ^:once Root
static om/IQuery
(query [this] `[{:people ~(om/get-query Person)}])
When I click on Delete button that is rendered as part of Person component, my app state changes well, and I can see that using (log-app-state) but my Root component doesn't get rerendered. Anyone knows why rerender doesn't happen?
@vmarcinko: are you defining the delete function in Root or in Person? If any delete function for a child isn’t defined in it’s parent, the parent won’t be re-rendered
yeah, that’s the reason, you’ll have to defined the delete function in the parent and pass it to the child via om/computed
since om/transact!
triggers a re-render from the component passed in as the first argument
i'm maybe accoustomed with reactive libs that notice change in mdoel and re-render all components that depend on some model below
yeah, I think the issue is that you’re not technically changing the react key — you’re removing it
so om has to compensate for that
is om/computed and callbacks frequently used for that purpose, or there is some other way to re-render parent?
but I don’t know much about React so I’m kinda making things up that sound like they make sense 😬
that pattern is the expected pattern for both om and untangled, yes
@vmarcinko: So you need to understand the difference between Om and others. By default transact indicates that the subtree being acted upon should be re-rendered. That avoids the need to even look at the whole tree. Transact can specify follow-on reads that indicate other things should be re-rendered by what they query. Eliminates a lot of overhead.
So, technically, you can say (transact! this [(f) :parent-prop])
in the child and the parent will re-render; however, this breaks composition, because your child now acts upon knowledge of the parent
The "magic" of "I change something and the framework does a bunch of work to figure out what to do" kills your frame rate. Reactive atoms either re-render huge trees, or need to be embedded all over the place.
The abstraction of "trasactions should affect things locally" should never re-render a parent, because the child should not know about the parent. Thus the recommendation that transacts that affect the parent should be written there, and passed as callbacks. This is the REact way in general:
(dom/button #js { :onClick ... } "Click Me")
computed
is an unfortunate requirement that has to do with re-rendering not killing callbacks.
(my-child (om/computed props { :onClick ... }))
instead of (how it was originally) (my-child (assoc props :onClick ...))
. The latter doesn't work right for re-rendering reasons
The abstraction is then continued to "you should not need to know which components need to be updated, and we also don't want to do a bunch of dirty data checking"...so instead, say what data (abstractly) is affected, and Om will find the components that query for that and re-render those....that is the follow-on read
(transact! this '[(f) :people])
= Do mutation f, then re-render anything that queried for :people
@ethangracer: react-key is a cheat for forced refresh or entire UI...causes React itself to ignore shouldComponentUpdate
ok, thanx, i exactly wanted to ask that very question of the hting I just mutated appears in multiple places in UI tree, and me as one components doesn't want to know where are those, and computed callback seems a solution for only when one parent component is re-rendered, and there can be many components that need to re-render
callback only makes sense when you're trying to make the kind of isolation things like button
want
as a side note, it is also an additional reason to namespace your query keywords, so you don't accidentally over-render unrelated things
btw, do you always first try with callback, and use follow-on-reads only when there are bunch of components to re-render?
nope, use-case specific, according to what I said above: callbacks when you have direct parent-child relationship where callbacks make sense... e.g. :datePicked, :listItemAdded, etc. = callback Use follow-on reads when the things are more loosely coupled...e.g. added a friend, and the friend count on the other side of the UI should update.
adding a friend probably uses both
The parent (assuming it is listing friends) sends in a callback for :friendAdded into the UI for adding a friend, and the transact!
coded in the parent does a follow-on read for :friend-count
btw, I'm totoal UI/react noob, but when you menitoned that other frameworks with reactive way, although figure out themselves what UI portions must change can re-render huge trees - I thought that react is good exactyl for this purpose - huge virtual DOM is re-rendered, but real DOM is not, so its fast ,no?
that is the general promise of react: If you ask it to re-render something it only makes the DOM changes needed. However, VDOM is cheap, not free
that is why React has a shouldComponentUpdate
method...try to short-circuit whole parts of VDOM diff for the UI tree
And one more question - whole one app state atom thing is great, and one reason is that you can do history walk, but is there any practical limit to how long can such app be alive in one's browser, because we're basically keep consuming more and more space
you're not consuming more and more space. This history is limited to 100 steps by default.
yeah, i know about persistance structures, but default maps/vectors don't have history limit as I know, so I assumed here the same
when you mutate them, other snapshots of them are kept if someone has references to them
but "history" is something implemented by the app...in this case by Om. It keeps 100 refs to 100 steps of app state
There is a GC issue for things in your state...and you are responsible for that. Say you load 100 items, and then let the user page...say through 10000000 results. If you gather those up for each page they click and never clean any out, well, you're going to have problems. Nothing Untangled/Om can do for you.
it seems it will get spent very fast if you use set-string! with onChange handler for some text field
Also, the current serialization of the app state over the wire doesn't compress to take advantege of s.sharing. So at the moment a support request is way more expensive than it need be
@vmarcinko: I've found that it is sometimes a good idea for your follow on read 'keys' to be idents. So if a particular instance of a component needs to be updated give its ident as the follow on read. Most (actually all in my case) of the keys are at the root level, so specifying one of them as the follow on read just ensures that everything gets re-rendered, which is not what you would usually want to happen.
@currentoor: much better implementation of parallel loading coming. I'm going to merge it even. Much simpler.
@tony.kay: awesome! looking forward to it
@cjmurphy: what’s the syntax you use for that?
@currentoor: It's up. new jars on clojars for snapshot of client (server 0.4.7 is fine...didn't need to modify the server at all). The cookbook is updated with the recipe...and it is trivial to use....just add :parallel true
on any load-field
or load-data
@ethangracer: that is what you're needing for reports, too
@tony.kay: awesome, I’ll take a look at that soon as we go client-side
@ethangracer: It really is just the ident instead of the key. I'll give an example from my source.
(om/transact! cell `[(graph/remove-line {:graph-ident [:trending-graph/by-id 10300] :intersect-id ~id}) [:trending-graph/by-id 10300]])
huh, have you confirmed that it specifically targets the ident? I’m surprised because that isn’t part of om’s query syntax to my knowledge
@ethangracer: those are not queries...they are follow-on reads
ah, ok
I thought that follow-on reads weren’t ‘special’ so to speak
if you give just a keyword, it looks up ALL components that query that keyword, finds the queries that have to run to update them, etc.
that it just did a read of those keys by finding their components in the indexer
gotcha
so idents do work as follow-on reads, that is good to know @paul4nandez
but in general I would recommend the more abstract thing and do follow-on reads on keywords...idents can suffer from under-refreshing, since you might later extend your UI to use dependent data that is queried with similar keywords.
obviously they are supported for a reason...just noting that you're tying your refresh to a particular use of data, as opposed to the data itself
I never understood using keywords as follow on reads - because they are all at the root and it seems everything gets re-rendered.
when you do a follow-on with :xyz, it looks in ALL on-screen component queries for :xyz
sure, but ident is the same there...you're going to re-render the sub-tree of whatever you target
you always get a sub-tree re-render, because there is no telling how the data that changed might be used (or derived) further down
The keys I always thought of targeting must have been in top level of root - which no good - then I found using ident very good at specific targetting.
nope...it does what I said above. keyword -> indexer -> components that query for keyword -> re-render
it is an abstraction that lets you think about your data, instead of your UI. "Run this mutation, then re-render anything that asks for this kind of data"
In the above example I have a checkbox in a grid. One of many. If you check it then you want the graph to have that extra line in it. So you want the graph to re-render - thats what the ident as follow on does. Also I pass the cell to the parent. The transact happens to be done in the parent, but only the particular cell is re-rendered. So I achieved what I wanted.
Sure. I'm not saying idents don't work...just that you misunderstood follow-on reads
you could have something that has a different ident (e.g. a table) that queries for the same data. Doing a follow-on read for the query would re-render both....an ident would only re-render one