This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-01
Channels
- # adventofcode (11)
- # aws (8)
- # beginners (70)
- # boot (2)
- # cider (9)
- # cljs-dev (29)
- # cljsrn (2)
- # clojure (67)
- # clojure-android (2)
- # clojure-dusseldorf (5)
- # clojure-greece (12)
- # clojure-italy (4)
- # clojure-nl (3)
- # clojure-poland (3)
- # clojure-russia (5)
- # clojure-spec (80)
- # clojure-uk (9)
- # clojurescript (73)
- # core-async (17)
- # cursive (1)
- # data-science (5)
- # datomic (29)
- # emacs (5)
- # fulcro (257)
- # graphql (2)
- # hoplon (2)
- # jobs (2)
- # klipse (3)
- # leiningen (9)
- # lumo (4)
- # nyc (1)
- # off-topic (48)
- # om (7)
- # other-languages (11)
- # pedestal (4)
- # re-frame (18)
- # remote-jobs (1)
- # rum (10)
- # shadow-cljs (5)
- # spacemacs (20)
- # sql (5)
- # test-check (44)
- # unrepl (8)
- # yada (9)
Just noticed that transact!
has another arity that has ref
as a second arg: [r ref tx]
(usually it is [r tx]
). Is ref
where you pass in an ident? What's the purpose of ref
? I just discovered this while reading the code of fulcro-inspect.
@cjmurphy when do it the ref
gets in your mutation as part of the environment, it's a good practice to use the ref
to target the element on your mutations, this works as mechanism that you can use to trigger actions to any entity based on ref on your system
for example, check the default mutations of Fulcro, like set-props!
, it uses the ref
to target the data on the db
@currentoor never seen it…REPL screw up?
@grzm I don’t personally use CIDER, and have very little experience with it. The instructions are contributed. If they are in error, I’d appreciate help 🙂
Thanks @wilkerlucio. I can see on the definition side of defmutations that there's a ref in the env. In practical terms I just see using ref as easier than going to the effort of passing a parameter.
@cjmurphy I would not encourage that unless you’re tying a mutation to a component tightly
if the mutation gets executed from an arbitrary context, ref will be the ident of the component that invoked it
it could make life miserable…basically that arg is really used when you’re running transact!
on the reconciler, but you’re using a mutation that relies on ref
. Personally, I never code it that way because I feel parameters are much clearer, well-documented, code assist, etc.
Right - only use for mutations that only make sense when they are related to a component instance (an ident). Seems not that necessary for normal application programming - only needed for reading other people's code.
One thing, though: I think if you include a ref
to transact it does queue that ref for re-rendering. Of course, you can put that ident in the follow-on reads and get the same thing.
the ref in env is either derived from the component running the tx, or one you explicitly state. That ident is queued for refresh.
and using it to establish context is always going to be inferior to sending it in as a param to the mutation that needs it…because it causes coupling. That’s a theoretical opinion, and in practice it can be convenient
but, how often would this latter case come up? In practice, you’d probably only need it in one of those…so, again, don’t personally like it.
I really like the transact with ref
, in fulcro-inspect this feature is used to target components that are deep into the ui tree, without having to know exactly how to get there, I set some id's manually for then, so then I can just use their ref
to apply changes to then, without having to care where they are
oh, I see…so you’re using a mutation you wrote, that targets components you didn’t write?
but you want to write the mutation so it can be told which one…still, you could just be saying:
(transact this `[(do-thing {:to ident}) ident])
I guess I can see that making mutations for a “kind of thing”, which is common, would benefit from this when you have to target them from “outside” (e.g. server push)
yeah, and with the defmutation it just looks like calling functions, just in a different "env space"
if the change includes server changes, then I usually add the params as well
personally I still prefer the latter…it is more clear to me…it does not rely on context + params
I see the ref
case been more common in client-only components
or better saying, more on client-only mutations in general
Yeah, I just don’t see any goodness from it 😉 It seems like it just makes a function that is context sensitive, which leads to subtle bugs
things like: open that tab, select that modal, add this entry (local only)
well, just please keep it there 🙂
one question
I've having a performance problem a bit, I would like to know if you have an idea about how I could improve it
it's a very unusual case
I'm porting a big reframe app to fulcro
but we are doing it in steps
I have a screen filled with many many widgets
most of then in reframe at this point
we are adding a second fulcro widget there
so, in order to leverage a single query (which is the main purpose, have a single fulcro app there)
what I'm doing is a fulcro app, that contains a mixed of fulcro and reframe components inside of it
so we can swipe one by one of the widgets
but when I did this wrap, the fulcro components are getting slow to update =/
when I click on the things, I can feel the slow (I guess around 500ms), even when it's just a boolean change on the app state
all of then, which are 2 at this point
if I just make the fulcro part, they go fast
the problem seems to be around the mixed rendering
same react
with those subscriptions and all that signal stuff he does
let me try
yeah, that should make it more obvious. My guess is that something is getting triggered into looping…If you’re embedding reframe stuff in fulcro components, you’ll need to isolate them so the targeted refresh of fulcro doesn’t cause them to refresh.
any forceUpdate on a component (which is what Om Next does) will re-render the subtree (normally the Om factories prevent real rendering of children)…but reframe might treat that as the “app starting” again or something, because it might think it “owns” the whole tree
yeah, I'm guessing it's trying to update the whole thing on events
when a fulcro component updates (via (mutations/set-value!)
for eg), the rendering is localized to it?
how is it in 1.x?
In 1.x it is Om Next: set-value! will update the local component’s props, and trigger a refresh for that component, BUT without path-opt, it has to render from the root.
Om Next optimizes how much of the query it must run…but rendering happens from root without path-opt
humm, that sounds like an issue for the case I'm handling here
ah, ok
depends on follow-on reads…but in the case you described (`set-value!`), it should be local to that component….throw in some console logging 🙂
yeah, I have one in the main part, that seems to not be triggering
I have to add more into the reframe components to see if something is going on there
ok, this
tree is fine 🙂
but if that was just it, it shouldn't degrade performance when put aside many other stuff (and that is what's happening here)
seems like there is more to this story than I'm noticing here
as part of the query, I have the normal queries for the fulcro components, but I also have one "open" key there, that contains all the data for the reframe stuff
but the query for it is simple, just the keyword (just get whatever is there to pass down)
do you think that could be an issue?
I didn’t realize you were having fulcro manage reframe data…I thought you had reframe subs?
there are many moving parts on this system (yeah, not fun...), so, there is more to the app than this part
the app is huge
we are starting on a part of it
so, there is reframe -> fulcro -> reframe + fulcro
I have no way around it... we have to do it gradually
there is another part of the system that's just fulcro inside reframe, that part runs very well
you mean multiple fulcro apps?
that was the first approach, but if I do that I would have to run multiple queries and manage multiple widgets, so would be getting back on the actual problem we are trying to solve
the reason to do that is the composed query will be able to optimize because of the long range, if I distribute that I lose this
maybe I can do some work there, I want to upgrade to fulcro 2.0, but I'll probably have to do it on my time
and I want to finish at least fulcro-inspect before that XD
it's talking almost 1 second to the UI to respond (ok, in dev mode, should get a bit better with prod react)
at least only the fulcro parts are been affected, the reframe is running like before
It has to be that extra state. Could be path-meta
wasn’t as well-fixed as I thought.
humm, seems that something about the event handler can be, the response to the click itself is what is taking so long
it's calling the om/transact!
way more times than I expect (I expect 1, and a quick count seems like it's happening 20+ times)
check all the lines between the purple items, all are om/transact calls for some reason
the same component and action on devcards only triggers the om/transact twice
So, on a different topic: defsc
I’m tempted to make a few breaking changes for 2.x. Specifically, dropping support for the non-lambda versions of query/ident/initial-state. (leaving the non-lambda version of css stuff)…OR…just make them all be lambdas. The problem is consistency: Once we start making this
and props
appear from the outside context, I think it should be consistent.
I won’t back port the changes to 1.x…so it would be a “I know I have to do this to port” thing.
I could be a little more friendly and allow this, but it would cause breakage without errors:
(defsc Boo [this {:keys [db/id]} _ _]
{:ident [:boo/by-id id]
...})
it makes sense and reads well, but is incompatible with the current more error-checkable syntax of:
(defsc Boo ...
{:ident [:boo/by-id :db/id] ...})
for the initial state, I'm ok breaking it
but I think for the others we might want to keep the non-lamba versions too, the query is a bit rare to need the lamba version
but the syntax for the initial-state, the current is very non-intuitive (with the keyword on right side pulling from props)
yeah, but then it makes it confusing to newer users, and I don’t like that…“when do i use a lambda?”
Also, there’s the possibility that I can get rid of the :protocols
and add auto-discovery…like this:
(defsc Boo [this props computed children]
{:query (fn [] ...)
:some-other-ns.Protocol/method (fn [...] ...) ; in these cases, only `this` is supplied for you.
protocols are an open way to add more things, I don't think we should remove it
what you mean by auto-discovery?
if I can figure out how to scan for that protocol, then I could put empty methods for the ones you fail to mention
eliminating all of the “magic” of when you can use a lambda vs just data makes that an easiler thing to sell as the primary thing to build your UI with
Btw if you change all the defsc to lambda's will you lose the nice validation?
Yes, BUT, the destructuring will propgate to the lambdas, so Cursive, at least, will be able to highlight the errors
but what about custom protocols? If I want to add some protocol of mine
@wilkerlucio If I can figure out how to read the list of protocol methods from the Clojure runtime, I can auto-discover them…that’s the point 🙂
@mitchelkuijpers You’re liking the validation, too, I take it 🙂
I'm not following... I still don't get how I would add a custom protocol if you remove the :protocols
Yes I see it saves a lot of time, but if you remove it we will make our own macro, we want one anyway which also gives all the css classes and validates them
(defsc Boo [...]
{:your-protocol-namespace.ProtocolName/method-name (fn [args] ...)})
ok, now I got it 🙂
If I can autodiscover with arity, I can output any you omit with underscores for params
@mitchelkuijpers do you use Cursive?
No we are al spacemacs and vim users
@mitchelkuijpers what do you think of the initial-state “magic” in defsc?
We are just moving to 2.0 and started to use that 😛
But like I said do what is better for everyone if I want stuff Iam just going to port it to our own codebase
I’m trying to gather feedback…I do plan on doing what is best, but I’m not sure what that is 🙂
We actually like the magic, because we can do less things wrong which kinda helps 😛
That it looks at the queries you mean and does the right thing? is that the magic?
Yes that part, with the params
Yeah we do use that
{:initial-state {:people [{} {} {}]}}
means
(initial-state [_ _] {:people (mapv (partial Person %) [{} {} {}])}
(roughly)
Yes we use that
But we started on it yesterday so we can still change things around 😛
But we like that, makes it all very concise
the error checking won’t let you put in things that are not in your query, but sometimes you need to (in root for example).
I can (and actually have) made it do both…but as I’m writing the documentation I’m having to say things like “if you write it this way with that over there, then …”
for example, the 2.x version at the moment will let you do it either way, but if you do a lambda for query, then it has to force you to do it for initial state.
@mitchelkuijpers what’s the CSS validation you’re looking for? Is it something others would like?
@wilkerlucio thanks for the tip about fulcro! I have an existing Om app with a backend server in production. I was experimenting with Om Next to see what the migration will be like. And it’s VERY painful. From a cursory read of the Fulcro docs, it seems Fulcro has a server implementation too. Is it possible to use Fulcro without the make-fulcro-server
?
That the css classes that you destructure actually exist
I wanted that the other day as well…but the args order sucks there to keep bw compat
Yeah then you get a lot of [this props _ _ css]
ideas?
- I could auto-shove them into computed
…that could cause collisions, though.
- Tolerate the fact that they are after children, and only valid if you have a css entry
- Make a diff arg list order when you use css
I would go for the second option tbh, but not sure how this works if you don't use fulcro-css?
And then maybe only add it if you use css in that component that is a good idea
it’s fine…the macro generates code, so if you don’t use the option, it doens’t generate code that needs css
the rule would be that the 5th arg is only needed (allowed) if you add a :css entry to options
Yeah we would love that change
could also put it under a namespaced key of computed:
(defsc Boo [this props {{:keys [classname]} :fulcro-css/css} _ _] ...)
Yeah that is also a option
Then you don't have clashes
and when we decide to add more (protocols that want destructuring), this is extensible
Yes but maybe add computed under a extra key also then?
Not sure but I like the idea especially with extensibility
hm, yeah…computed really is a special thing…munging them essentially means this:
(let [{{:keys [classname]} :fulcro-css/css} (merge {:fulcro-css/css (css/get-classnames)} (om/get-computed this))]
...)
in the generated codeit gives priority to computed, whereas css is possibly a lot more common a thing to use
Yeah we use that way more, because we only use fulcro-css
And sometimes you need computed
@daniel.dyba yes you can, I personally don't use the server stuff of fulcro, just the client
@daniel.dyba pathom from @wilkerlucio is very interesting 😉
Yeah to me that also looks better, the other option does look a bit like a hack
yeah a lot of ppl don’t seem to know how to do nested destructuring…not even sure I typed it right there 🙂
I tend to be against adding more and more to arglist... but on this case I think it's ok
so then the question is should it be arg 3 or 5? 3 breaks existing code, but “feels better” to me
It might be fixable with a shell script.. but you could also add it before children. I can imagine not a lot of people use that with react 15 because of all the annoying warnings it gives
:thumbsup:
@mitchelkuijpers I’m going to let you guys write the validation for it, though…I don’t want to parse garden 🙂
Sure hand that to me and @timovanderkamp
We can fix that for you no problem
We'll see even without validation it is a nice
I think in fulcro-css it already needs those keys somehow, can't remember from the top of my mind
Don't hesitate to ask @timovanderkamp he might know some edge cases
I gotta go, good talk ^^
It just occurred to me that I can make the final arguments of defsc optional so we don’t have all of the underscores lying around 😜
user=> (:sigs fulcro.client.primitives/IQuery)
{:query {:name query, :arglists ([this]), :doc "Return the component's unbound static query"}}
Gotta love dynamic languages 🙂