This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-11-24
Channels
- # aws (14)
- # beginners (111)
- # boot (12)
- # cider (1)
- # cljsrn (7)
- # clojure (65)
- # clojure-dusseldorf (1)
- # clojure-germany (7)
- # clojure-greece (10)
- # clojure-italy (13)
- # clojure-poland (7)
- # clojure-russia (7)
- # clojure-spec (53)
- # clojure-uk (29)
- # clojurescript (27)
- # community-development (9)
- # cursive (2)
- # data-science (1)
- # datomic (17)
- # emacs (16)
- # events (6)
- # fulcro (155)
- # graphql (8)
- # instaparse (1)
- # leiningen (30)
- # lumo (29)
- # om-next (3)
- # other-languages (46)
- # pedestal (11)
- # portkey (7)
- # re-frame (13)
- # reagent (6)
- # ring (8)
- # rum (1)
- # shadow-cljs (75)
- # sql (1)
- # timbre (3)
- # unrepl (128)
Oh man…totally off-topic: Just made the best pecan pie ever…probably on the planet. Hand-toasted some pecans, used duck eggs and goat butter plus a CUP of maple syrup, and a dash of salt = pie bliss…
sounds delicious 🙂
can you send a picture?
I thought that might be overkill. I am gluten-free as well, so the crust is made of almonds.
Turns out there was a bug in Om Next’s code on master related to refresh under adv optimizations. It is unreleased code in Om Next, but those of you using Fulcro 1.0, beware if Om bumps without a patch. The problem is how mounted?
is implemented. Just pushed a fix to 2.0.0-SNAPSHOT.
Just pushed Fulcro CSS 2.0.0-SNAPSHOT to clojars. Works with Fulcro 2.0 without pulling in Om Next now.
@wilkerlucio Finally got a chance to try the new fulcro-inspect. Very nice indeed 🙂
@tony.kay Need help, I just want use fulcro-datomic in fulcro-template, when (go), get a fatal log: Transaction function failed to return a list of transactions! fulcro-template.migrations.initial-20171124
I had checked the code, and found the problem is come from all-migrations* in fulcro-datomic.datomic.schema.
because the txn is like
[{:db/index false, :db/unique :db.unique/value, :db/valueType :db.type/string, :db/noHistory false, :db/isComponent false, :db.install/_attribute :db.part/db, :db/fulltext false, :db/cardinality :db.cardinality/one, :db/doc "", :db/id #db/id[:db.part/db -1000221], :db/ident :file/path} {:db/index false, :db/unique :db.unique/value, :db/valueType :db.type/string, :db/noHistory false, :db/isComponent false, :db.install/_attribute :db.part/db, :db/fulltext false, :db/cardinality :db.cardinality/one, :db/doc "", :db/id #db/id[:db.part/db -1000222], :db/ident :file/name} ]
and
(if (contains-lists? txn)
(let [data-fn (meta txn)]
(vector (migration-keyword nspace) (merge {:txes txn} data-fn)))
(do
(timbre/fatal "Transaction function failed to return a list of transactions!" nspace)
[]))
the
;; need this for testing..fatal is a non-mockable macro
(defn contains-lists? [l]
(every? sequential? l))
@tony.kay thank you 🙂, we are getting there, I'm still completing the network
tab, yesterday I the table designs and details, but currently there is no way to know which network triggered the request, finishing that the next is the element 🙂
@tpliliang Yeah, the nesting is a bit strange on that one…
I assume it’s not possible to get computed properties within ident
, since it’s a static method? e.g.
static om/Ident
(ident [this props]
(let [{:keys [::option-key]} (om/get-computed this)]
[:option/by-key (option-key props)]))
no way to do this dynamically?during normalization…where the only thing available is the cold hard props of the incoming data (from the network)
ident is also used during UI refresh..but at that point the identity has to have already been established, so it makes no sense.
the ident can’t change based on parent ideas….it is already in the database at some specific ident 🙂
right, makes sense. I’m building a select widget, and I don’t always know the shape of the queried options, so I allow the consumer of the widget to specify their own option key function, but this is known at compile time so there must be some way to accomplish, no?
So, if you want a reusable widget, then you want well-known structure of some kind. I recently added a demo with cascading dropdowns
https://github.com/fulcrologic/fulcro/blob/develop/src/demos/cards/cascading_dropdown_cards.cljs
I’d give the select widget itself a schema (e.g. namespaced props that are spec’d) and map the server data onto that…
I was lazy and just made the server understand the prop names the widget wanted, but you could also use a post-mutation or something to morph it
well that’s the only thing that I know for sure. because the select widget is used again tons of different things
I was going the direction of not normalizing initially, but I’d like to set :focused? on the options individually, and it seemed like an ident would be the way to get that address without iterating over them all
So, do you want your real database entities to be the target of selection, or are these for selecting some crap in the UI that you invent as you invent the UI?
ah, hmm. I don’t want the real database entities to be the target of selection. good point
I think this is “selecting some crap in the UI”. I’m setting the focused option in the dropdown so that when, say, a person presses arrow down/up I can update (move focus)
Ah, so you’re making a more interactive thing…ok. So your select control itself needs to keep track of either an offset index or the identity of the item focused
actually, the former could be used by the parent to pass in computed data to tell the child to do it…lots of options
when I designed this previously (in quiescent) I just set a focused index on the parent, however this forces every option to update when that changes. So I was thinking I’d try setting focused on the actual option
but the data model is central:
{ :select-box/id :which-thing-you-want
:select-box/focus-index 0
:select-box/items [ [:select-item/by-id :thing-1] [:select-item/by-id :thing-2] ]}
VDOM diff will keep the children that have not changed from updating…for that matter, Fulcro’s built-in shouldComponentUpdate won’t refresh anything that didn’t have data changes
oh, in the approach I was describing I’d be passing in the focused-index to each option, so when it changed shouldComponentUpdate would trigger
so, the latter is more general purpose, since it just becomes an invariant based on type (single or multi)
if you put the data in the item, then you’re goign to either have to clear it on all and set it on one, or remember where it was set…easy source of bugs
but no reason to do that, derp. I can just compute :focused? while mapping over the options before passing them their props, no?
as you get better at this you’ll continue have these “derp” moments. I certainly have
So, this is cool: I am working on cleaning up the dynamic queries, and found a pretty easy way to make them not require any source changes from 1.0 -> 2.0 🙂
hmm. so when I use the computed approach, newly focused options are updated, however previously focused options do not update. Am I missing a follow on read or something?
you’re mapping over all of the options from the parent, with a computed that gives them t/f for focused?
Ah, are you using a callback to the parent to change the focus? (e.g. is the key event going to the parent, and the transact happening there?)
(mapv (fn [option] (ui-option (computed option {:focused? (= (:index option) current-selection-index)}))) options)
yes to 1, no to 2. my transact to change focus is getting passed this
from the option. So i should make the focus fn a computed as well
you’re changing parent state (selected index), so the parent should run that transact!
…send an onSelect via computed
UI Refresh rules are rather simple:
- The component running transact!
will re-render
- If the component has an ident, anything on the UI with the same ident value with refresh (I think that’s true)
- Otherwise, follow-on reads.
cool. I’ve got it working with computed. however all options are rerendering, not just the two that need the change
shouldComponentUpdate on them should short-circuit unless you’re actually changing data being sent to them
I’ve always used map-indexed for this sort of this (in quiescent). not sure how to approach
It should be fine…I would ask why you’re worried about a VDOM diff on something so small? Or is it like 1000's of options?
There could be a bug in Om…but if the data, state, and computed don’t change, then render should not get called.
oh, well I guess i never was in the past, however since I’m redoing widgets that I’ve written before I thought I might try for improvements. Also i figured whatever approach caused the fewest renders might be more idiomatic anyway.
The only app I’ve seen with speed problems so far in the Om Next universe has more to do with writing inefficient queries. That can kill you.
it is why the UI routers and dynamic queries exist, so you don’t end up with over-querying to feed the “current screen” of UI. That will be where your optimization effort will go. Don’t worry about shouldComponentUpdate stuff. If there’s a bug there, it’ll get fixed.
right. yeah. I mean our old quiescent app isn’t terrible, and our render loop is literally recursive calls to .requestAnimationFrame. so this will already be much better
Fulcro 2.0.0-alpha4 on clojars. Removes the need for IDynamicQuery, makes your Fulcro 1.0 app API compatible with 2.0 for queries on components. The set-query!
API still uses the (optional) new qualfiers based on factories…but this fixes composition as well, and was fairly easy to do…mostly I deleted code (added like 2 lines, removed like 20).
so here’s why: What happens if we re-render an Option by itself? I can query for it’s props via the database, and re-run JUST the render of that component…where will ::index and :react-key come from? Select isn’t involved…
That is why computed exists…If it didn’t come from the database, you need to let the system know it is extra data that has to be kept around should the component get updated (via a mutation/re-render) in isolation
ah, I see. I thought computed was just to get around the fact that passing functions props would always cause rerenders, but, as the name suggested, it’s computing and storing data
moving react-key doesn’t appear to work, however. I’m not specifying a keyfn when buildng the ui-option factory, and I was using react-key to pass it in. Now it’s barking at me for not providing a key
so, if you put that on props, it will end up being your key. Let me think about the targeted refresh on that one…
the targeted refresh calls forceUpdate
, so I don’t knwo that the key would even get checked
we previously allowed people to provide their own key-function when invoking a widget like this, but I like your idea of just ensuring that there is some known structure at design time. be that a :db/id, or some client namespaced key that the server is sure to provide
it always pays to have that kind of clean data model. So much easier to reason about too
so, were you saying that passing in the index would be causing a rerender in all options. like i have it in the example above?
if a react key changes in any element, that entire subtree is guaranteed to be fully re-rendered
I follow on the hot code reload. but this is triggering rerender in all options between code reloading
I realize the vdom diff is still giving me perf, but now I’m just obsessing about how to potentially prevent render from being called on each option 🙂
shouldComponentUpdate will return false
if props and state have not changed. So, log your props and state and see what’s changing
isn’t that expected? You didn’t set any did you? (I assume you’re talking about component-local state, i.e. (get-state)
)
Another note to those that might be interested (@wilkerlucio @gardnervickers @mitchelkuijpers @currentoor?) That long-standing issue of the compiler hack that breaks adv compilation…I have an idea how to fix it and get rid of the compiler hack 🙂 https://github.com/fulcrologic/fulcro/issues/67