This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-04-15
Channels
- # announcements (10)
- # beginners (113)
- # calva (2)
- # cider (75)
- # clj-kondo (1)
- # cljdoc (2)
- # clojure (142)
- # clojure-europe (11)
- # clojure-gamedev (6)
- # clojure-italy (7)
- # clojure-nl (8)
- # clojure-spec (3)
- # clojure-uk (50)
- # clojurescript (47)
- # cursive (7)
- # data-science (22)
- # datomic (12)
- # dirac (3)
- # events (1)
- # fulcro (114)
- # gorilla (1)
- # jackdaw (5)
- # joker (3)
- # kaocha (10)
- # leiningen (1)
- # liberator (2)
- # mount (6)
- # nrepl (1)
- # off-topic (16)
- # pathom (34)
- # pedestal (3)
- # re-frame (19)
- # reagent (11)
- # remote-jobs (5)
- # shadow-cljs (127)
- # spacemacs (12)
- # test-check (15)
- # tools-deps (8)
- # vim (4)
@UG7NHNTE3 Yep, the latest version from is
Version
1.0.11
Updated
April 12, 2019
@U3LP7DWPR Thanks.
I've been wondering the best way to model something in om.next and I guess it probably applies to fulcro too. I have components that are selectable and can appear in multiple levels in the dom tree. What I'm trying to work out is the best way of storing the selected element on state, and the best way of propagating it to all the selectable components (they need to update to indicate which one is now selected on click).
It works to query for the selected element in the root component and pass this down through the entire tree. I'm not sure if there is any other way of doing this that involves the indexer, without having to re-render the entire tree?
It's slow and i also have problems transacting from components deep in the tree, because they or their parents don't have queries
@danielstockton you can use the same ident on the components that share data, that's the way to go on both om.next and fulcro, so when you update on the DB everybody will be looking at the same place, updating then all, a :ui/selected?
key can do the job
Ok but what would the query look like on these components? Don't I have to workaround the 'everything must compose from root' rule?
Can i just stick a query on these components that doesn't necessarily compose back?
@danielstockton you need to make references as you go, the query would be simple, juts [:some-entity/id :ui/selected?]
, just do that for every component, using the same ident so they point to the same place, if you are rendering it multiple times on the screen I expect it to already have some way to referencing the same point, there is no generic answer since that heavily depends on how your UI is structured
Ok, i'll try something along those lines. Thanks
@danielstockton Let me chime in a moment. Is this really an Om Next questions (i.e. is that what you’re using)?
Yes @tony.kay, om.next is what I'm using atm. Is fulcro considerably different in how i'd model this?
so Om Next has the parser…so you can model any attribute in the tree via some invented keyword and then write logic in the parser to satisfy that query. Did I understand you right that you’re modelling something like a radio button situation?
and since the parser can use parameterized queries, you have power there to “make up” some additional meaning for queries.
Fulcro has the opinion that while this is a more powerful model in theory, it does not scale well in practice, so it leverages a more data declarative approach: your state is what matters, and specialized logic is more easily understood in mutations and local UI logic.
so yes, I might model a particular problem quite differently between the two, even though they share some central concepts and query language.
In Om Next I have no guarantee, as a reader (of the UI code), of what a query means…the parser can change contexts as it goes and do pretty much anything…but the more of that you do that the more confusing everything becomes, so I doubt anyone would actually do that in practice. In Fulcro you can just “follow the data”. The query’s primary usefulness, IMO, is for the full-stack story: How to I load/normalize/insert a tree of data into my local state, and how do I get back out what this particular bit of UI needs?
So, back to your original question: are you trying to model the basic idea of a radio button? One thing selected causes others to unselect?
Yes, that's exactly what i'm doing
I understand what you mean regarding om next and the parser allowing pretty much anything which can become quite hairy. Less familiar with how it would be done in fulcro.
And the queries usefulness is being able to grab all the state you need in a single query, as opposed to lots of other options like reagent/rum/re-frame which let you grab state here and there however you please.
OK, so the first thing to realize is that there is one fact of interest in a radio button situation: which thing is selected….you would never ever model that with :ui/selected
because that “denormalizes” that fact.
Yes, that's actually how im doing it now. I story an id of the selected item, and in each item i check if its selected...
The only problem is transacting when there is no query deep in the tree, and efficiency of re-rendering the entire tree
Right, why the parent and not the element itself?
Om Next “efficiency” is up to you making sure the component in question has a query and composes to root…no compromise there
if the component also has an ident and you turn on the optimization for it, then it can run the query from that component, otherwise the query always runs from root…this is a necessity in order to get the flexibility of the parser…it cannot default to “on” because your parser needs to gaurantee it can do ti.
Yeah, but the way i did it was query in root and passing it down all the way through the tree... i think i can solve that with the 'ident loop' idea
Turn on, you mean :root-query true
on the AST? (remembering something of the kind)
Yeah, i'd have each component include that same ident, and include the query from the child
But could something like [:page/els :selected]
not be the identity of the currently selected thing?
efficiency of rendering the tree has two components in these libraries: 1. Can I get the data for the component in question without running the query for everything 2. Can I avoid doing the work of VDOM on side branches? (1) only is possible if the query is there (2) Is only possible if you make the components “true components” (e.g. defui shouldComponentUpdate returns false on the side branches)
So, I’m going to back off of Om Next for the moment…take the parser out of the equation. I think it makes the whole thing very difficult to talk about because you’ve got “too much rope”.
(om/get-query Child)
all the way back to root, pulling that ident up the tree
2) is definitely true of any react wrapper
i.e. don't make your render too big, compose it of components that can easily have their props compared
Here’s how to model it in Fulcro:
(defsc Car [this {:car/keys [id name]} {:keys [selected onSelect]}]
{:query [:car/id :car/name]
:ident [:car/id :car/id]}
(div
(input {:type "checkbox" :checked (= id selected) :onClick #(onSelect id)])})
...))
(defsc CarList [this {:car-list/keys [cars]}]
{:query [:car-list/selected-car {:car-list/cars (prim/get-query Car)}]
:ident [:car-list/id :car-list/id]}
(map (ui-car #(prim/computed % {:selected selected-car :onSelect #(prim/set-value! this :car-list/selected-car %})) cars))
Any stateful component in Fulcro and Om Next will compose queries to root…but that doesn’t mean you think about it any more than one level at a time.
so, the temptation to “keep the query close to root” in Om Next is simply an indicator of the pain I’m talking about that led me to make Untangled/Fulcro.
I have a clear way of loosening the requirement of “compose to root” (slated for Fulcro 3), but to be honest we’re debating if it would actually be an improvement, because it turns out that a composed query gives you some interesting novel power.
Right, so fulcro somewhat automates the query composition?
Fulcro just has you compose initial state alongside the query in a tree, auto-detects it on startup, and normalizes that using the query
and Fulcro gives you a clearer way of doing all of the loading for the components that are not part of your initial state….Om Next has you embed all of that mess in a parser
Might be missing something. I don't see in the above example what links the two queries
and CarList would compose to it’s parent…but CarList doesn’t need to know anything about that
(at any given level)…which is why it isn’t a big deal IMO…esp if you have initial state to set up the state-based ident linkages at start time
What Wilker was getting at is that two different “views” of a given thing (e.g. CarForm, CarListItem, Car) all should have the same ident, and therefore share the same place in state….they are diff views of the same normalized data.
In a “list of cars” the parent might want to allow you to select 3 of them…in a radio, only one, etc.
Ok, yep. Doing it like this, with the parent rather than all the children 'knowing' who is selected; would it not be less efficient than having that in the child's query and triggering a re-read of that ident?
(though in the former I’d probably put :ui/selected on that component
and drop the parent control)
every one of those children has a shouldComponentUpdate that will prevent any real work on a ref compare.
Yep, right. It's then important to do what was said above, and make sure CarList is split into subcomponents and not a really heavy render
Because you're using computed props? Or what's wrong with what you wrote?
Right, yep
so let’s say that you wanted to query for the “who is selected” fact on each child. Don’t you have to re-render them all in a radio situation?
so unless you put the checkboxes on the parent I think you’re screwed, so to speak 🙂
Yep, very good point
Fulcro is more about cleaning up the data model than being the fastest thing on the planet…the query processing overhead usually dwarfs the React CPU
Yes, same with persistent immutable data structures
but I work on some pretty varied UIs with clients, and it is still fast enough in most cases without much trouble
Makes sense, usually that's a sensible trade-off
and I know how to make it about 10-20x faster than it currently is 🙂 Just need to find the time
I also needed a hover state as well as selected, and for that i used component local state and an atom to hold the last hovered (to unhover on mouseout). Seemed to work pretty well and fast, and I guess for something so fleeting it isn't important to be in the app state
(Om Next actually wins on performance at the moment, I removed some of it’s optimizations because they were not recommended beyond React 15)
What optimizations were not recommended beyond React 16?
Yes, component local state but i also needed them all to be able to know what was last hovered... hence the atom, but outside app state
Hmm right, to force re-rendering only a component identified by the indexer to have changed?
Problem is, they don't all share a common parent, they're nested at different levels in the tree
It's a kind of editor built itself out of components, and various elements in the tree are selectable in order to edit them
As in, made it part of the app db?
Would there be disadvantages to just using an atom? It still needs to compose right? Isn't that similar to what we was needed for the selected item?
I got a bit creative and all the logic is in mouse-out and mouse-enter events, which triggers updates on each components local state to refresh them if necessary
Yeah, it all needs a bit of reorganization based on what we've discussed
Sure, thanks a lot!